From 818e9f8b4cb8b2374b6efcb4e66cdc76c98cc2ec Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Thu, 15 Nov 2018 15:28:35 +0100 Subject: [PATCH 001/223] 3417 - don't use legacy action for create method --- src/Umbraco.Web/Trees/MacrosTreeController.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/Trees/MacrosTreeController.cs b/src/Umbraco.Web/Trees/MacrosTreeController.cs index 3f925eef8d..0649378aaa 100644 --- a/src/Umbraco.Web/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/MacrosTreeController.cs @@ -59,11 +59,8 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { //Create the normal create action - menu.Items.Add(Services.TextService, opensDialog: true) - //Since we haven't implemented anything for macros in angular, this needs to be converted to - //use the legacy format - .ConvertLegacyMenuItem(null, "initmacros", queryStrings.GetValue("application")); - + menu.Items.Add(Services.TextService); + //refresh action menu.Items.Add(new RefreshNode(Services.TextService, true)); From e8818b36bd80160ccfdd350bfed9a53a6ac2b7b9 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 26 Nov 2018 07:49:32 +0100 Subject: [PATCH 002/223] Media could not be moved to the root (The root was not available as target) --- src/Umbraco.Web/Models/Trees/TreeNode.cs | 1 + src/Umbraco.Web/Trees/ApplicationTreeController.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Models/Trees/TreeNode.cs b/src/Umbraco.Web/Models/Trees/TreeNode.cs index 01aa78ca36..fa1f8be310 100644 --- a/src/Umbraco.Web/Models/Trees/TreeNode.cs +++ b/src/Umbraco.Web/Models/Trees/TreeNode.cs @@ -35,6 +35,7 @@ namespace Umbraco.Web.Models.Trees CssClasses = new List(); //default Icon = "icon-folder-close"; + Path = "-1"; } [DataMember(Name = "parentId", IsRequired = true)] diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index c1192b6909..dd5e38e5fa 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Net; @@ -21,7 +22,7 @@ namespace Umbraco.Web.Trees [AngularJsonOnlyConfiguration] [PluginController("UmbracoTrees")] public class ApplicationTreeController : UmbracoAuthorizedApiController - { + { /// /// Returns the tree nodes for an application /// @@ -184,6 +185,7 @@ namespace Umbraco.Web.Trees //assign the route path based on the root node, this means it will route there when the section is navigated to //and no dashboards will be available for this section sectionRoot.RoutePath = rootNode.Result.RoutePath; + sectionRoot.Path = rootNode.Result.Path; foreach (var d in rootNode.Result.AdditionalData) { From a50a46f9fa233dc4deb6a8015ef52f696f382b44 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 26 Nov 2018 07:50:15 +0100 Subject: [PATCH 003/223] Alt of "close dialog" buttons was not functioning on the success message --- src/Umbraco.Web.UI.Client/src/views/content/copy.html | 2 +- src/Umbraco.Web.UI.Client/src/views/content/move.html | 6 +++--- src/Umbraco.Web.UI.Client/src/views/documenttypes/copy.html | 2 +- src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html | 2 +- src/Umbraco.Web.UI.Client/src/views/media/move.html | 4 ++-- src/Umbraco.Web.UI.Client/src/views/media/restore.html | 2 +- src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html | 2 +- src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/copy.html b/src/Umbraco.Web.UI.Client/src/views/content/copy.html index 03a024c439..14ea54cf42 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/copy.html @@ -14,7 +14,7 @@ {{currentNode.name}} was copied to {{target.name}} - +

diff --git a/src/Umbraco.Web.UI.Client/src/views/content/move.html b/src/Umbraco.Web.UI.Client/src/views/content/move.html index 708c3d3f82..c713bd90e7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/move.html @@ -13,13 +13,13 @@

{{currentNode.name}} was moved underneath {{target.name}}
- +

Choose where to move {{currentNode.name}} - to in the tree structure below + to in the tree structure below

@@ -29,7 +29,7 @@
- {{currentNode.name}} was copied underneath {{target.name}}
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html index af0ce58227..aada5193ec 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html @@ -22,7 +22,7 @@
{{currentNode.name}} was moved underneath {{target.name}}
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/media/move.html b/src/Umbraco.Web.UI.Client/src/views/media/move.html index 6d93eb4e22..15d38a6130 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/move.html @@ -13,7 +13,7 @@
{{currentNode.name}} was moved underneath {{target.name}}
- +

@@ -23,7 +23,7 @@

- +

{{currentNode.name}} was moved underneath {{target.name}}

- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html b/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html index 3d8c3b0845..2f2fe336b0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html @@ -22,7 +22,7 @@
{{currentNode.name}} was copied underneath {{target.name}}
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html b/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html index 1ae686f5d5..2230f4a1a8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html @@ -22,7 +22,7 @@
{{currentNode.name}} was moved underneath {{target.name}}
- +
From cb7c1f9bbda57f447e1ea6b4c3c274c34dc12585 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 4 Dec 2018 11:18:12 +0100 Subject: [PATCH 004/223] use table for installed packages --- .../src/views/packages/views/installed.html | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html index a015748078..3c443e0bac 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html @@ -7,29 +7,33 @@
Installed packages
-
- -
- -
- - -
- -
-
{{ installedPackage.name }}
-
- {{ installedPackage.version }} | {{ installedPackage.url }}| {{ installedPackage.author }} -
-
- -
- Uninstall -
- -
- -
+ + + + + + + +
+
+ + +
+
+
{{ installedPackage.name }}
+
+ {{ installedPackage.version }} | {{ installedPackage.url }}| {{ installedPackage.author }} +
+
+
+ + +
From 04e8fc7fa3e1c5ff0925710fd1c1c334b4348782 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 4 Dec 2018 11:18:32 +0100 Subject: [PATCH 005/223] fix missing form from install local package --- .../src/views/packages/views/install-local.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html index f7843fb0fc..7f22b7ace8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html @@ -4,7 +4,7 @@
-
+
Install a local package by selecting it from your machine. Only install packages from sources you know and trust.

- +
From bd455aaede8a6a354cb7d3fc4f20a224fd21c898 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 4 Dec 2018 11:19:08 +0100 Subject: [PATCH 006/223] fixing up styles to better fit new UI --- .../components/umb-package-local-install.less | 5 +- .../src/less/components/umb-packages.less | 67 +---- .../src/views/packages/views/repo.html | 270 +++++++++--------- 3 files changed, 148 insertions(+), 194 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-package-local-install.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-package-local-install.less index 75f58f983b..99759fcee7 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-package-local-install.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-package-local-install.less @@ -15,7 +15,7 @@ height: 300px; border: 2px dashed @gray-8; border-radius: 3px; - background: @gray-10; + background: @white; display: flex; flex-direction: column; justify-content: center; @@ -74,7 +74,6 @@ // Info state .umb-info-local-items { - border: 2px solid @gray-8; border-radius: 3px; background: @gray-10; display: flex; @@ -84,6 +83,8 @@ margin: 0 20px; width: 100%; max-width: 540px; + background: @white; + box-shadow: 0 1px 1px 0 rgba(0,0,0,.16); } .umb-info-local-items a { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index e2cfb0bded..a517605c4a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -23,9 +23,7 @@ .umb-packages-search { width: 100%; - background: @gray-10; border-radius: 3px; - padding: 30px; box-sizing: border-box; } @@ -49,60 +47,14 @@ } .umb-packages { - margin: 0 -10px; - display: flex; - flex-wrap: wrap; + display: grid; + grid-gap: 20px; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); } // Cards .umb-package { - padding: 10px; box-sizing: border-box; - flex: 0 0 100%; - max-width: 100%; -} - -@media (min-width: 768px) { - .umb-package { - flex: 0 0 50%; - max-width: 50%; - } -} - -@media (min-width: 1200px) { - .umb-package { - flex: 0 0 33.33%; - max-width: 33.33%; - } -} - -@media (min-width: 1400px) { - .umb-package { - flex: 0 0 25%; - max-width: 25%; - } -} - -@media (min-width: 1700px) { - .umb-package { - flex: 0 0 20%; - max-width: 20%; - } -} - - -@media (min-width: 1900px) { - .umb-package { - flex: 0 0 16.66%; - max-width: 16.66%; - } -} - -@media (min-width: 2200px) { - .umb-package { - flex: 0 0 14.28%; - max-width: 14.28%; - } } .umb-package-link { @@ -114,10 +66,11 @@ box-sizing: border-box; height: 100%; width: 100%; - border: 1px solid @gray-9; border-radius: 3px; text-decoration: none !important; transition: border-color 100ms ease; + background-color: @white; + box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16); &:hover { border-color: @turquoise; @@ -151,15 +104,8 @@ // Info .umb-package-info { - padding-right: 15px; - padding-bottom: 15px; - padding-left: 15px; - padding-top: 15px; + padding: 15px; text-align: center; - background: @gray-10; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - border-top: 1px solid @gray-9; } @@ -251,6 +197,7 @@ border-bottom: 1px solid @gray-8; border-right: 1px solid @gray-8; padding: 10px 0; + background: @white; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index 7b4b960c2c..fc272c86ff 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -27,7 +27,7 @@

Popular

-
+
@@ -61,7 +61,7 @@

New Releases

Results for '{{ vm.searchQuery }}'

-
+
@@ -129,147 +129,153 @@
-
{{ vm.package.name }}
+ + +
{{ vm.package.name }}
+
+
+ + -
- - - - - + +
-
- - - - - - - -
- -
-
- -
- + + - -
+ action="vm.downloadPackage(vm.package)" + label-key="packager_packageInstall"> + + + + + + + +
+ +
+ + +
+ +
+
{{ vm.package.ownerInfo.owner }}
+
+ {{ vm.package.ownerInfo.owner }} has {{ vm.package.ownerInfo.karma }} karma points +
+
+
+
+
+ + + +
Information
-
{{ vm.package.ownerInfo.owner }}
-
- {{ vm.package.ownerInfo.owner }} has {{ vm.package.ownerInfo.karma }} karma points + +
+
Owner:
+
{{vm.package.ownerInfo.owner}}
+
+ +
+
Contributors:
+
+ {{ contributor }} +
+
+ +
+
Created:
+
{{vm.package.created | date:'yyyy-MM-dd HH:mm:ss'}}
+
+ +
+
Current version:
+
{{vm.package.latestVersion}}
+
+ +
+
.NET Version:
+
{{vm.package.information.netVersion}}
+
+ +
+
License:
+
{{vm.package.licenseName}}
+
+ +
+
Downloads:
+
{{vm.package.downloads}}
+
+ +
+
Likes:
+
{{vm.package.likes}}
+
+ +
+ + + + + +
Compatibility
+
This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be gauranteed for versions reported below 100%
+
+
+ {{compatibility.version}} + ({{compatibility.percentage}}%) +
+ + +
+
+
+ + + +
External sources
+ -
-
- -
-
Information
-
- -
-
Owner:
-
{{vm.package.ownerInfo.owner}}
-
- -
-
Contributors:
-
- {{ contributor }} -
-
- -
-
Created:
-
{{vm.package.created | date:'yyyy-MM-dd HH:mm:ss'}}
-
- -
-
Current version:
-
{{vm.package.latestVersion}}
-
- -
-
.NET Version:
-
{{vm.package.information.netVersion}}
-
- -
-
License:
-
{{vm.package.licenseName}}
-
- -
-
Downloads:
-
{{vm.package.downloads}}
-
- -
-
Likes:
-
{{vm.package.likes}}
-
- -
-
- -
-
Compatibility
-
This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be gauranteed for versions reported below 100%
-
-
- {{compatibility.version}} - ({{compatibility.percentage}}%) -
- - - - -
-
- -
-
External sources
- - -
+ +
From a4bdcf99b19e5a85d3f20661bbd5db3950d92a88 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Dec 2018 10:36:20 +0100 Subject: [PATCH 007/223] wip create package editor --- .../src/common/services/overlay.service.js | 5 + .../src/views/packages/edit.controller.js | 154 ++++++++++++ .../src/views/packages/edit.html | 227 ++++++++++++++++++ .../src/views/packages/overview.controller.js | 6 + .../packages/views/created.controller.js | 84 +++++++ .../src/views/packages/views/created.html | 45 ++++ 6 files changed, 521 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packages/edit.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packages/views/created.html diff --git a/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js b/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js index 6c50e58490..6de0b4170b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js @@ -27,6 +27,11 @@ overlay.position = "center"; } + // use a default empty view if nothing is set + if(!overlay.view) { + overlay.view = "views/common/overlays/default/default.html"; + } + // option to disable backdrop clicks if(overlay.disableBackdropClick) { backdropOptions.disableEventsOnClick = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js new file mode 100644 index 0000000000..a031baa26d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -0,0 +1,154 @@ +(function () { + "use strict"; + + function EditController($location) { + + const vm = this; + + vm.showBackButton = true; + + // open all expansion panels + vm.propertiesOpen = true; + vm.contentOpen = true; + vm.filesOpen = true; + vm.actionsOpen = true; + + vm.back = back; + vm.createPackage = createPackage; + vm.save = save; + + function onInit() { + // load package + + vm.package = { + "name": "My package" + }; + + vm.documentTypes = [ + { + "name": "Home" + }, + { + "name": "Blog" + }, + { + "name": "Blog Post" + }, + { + "name": "News" + }, + { + "name": "News Item" + }, + { + "name": "Contact" + }, + { + "name": "About" + } + ]; + + vm.templates = [ + { + "name": "Home" + }, + { + "name": "Blog" + }, + { + "name": "Blog Post" + }, + { + "name": "News" + }, + { + "name": "News Item" + }, + { + "name": "Contact" + }, + { + "name": "About" + } + ]; + + vm.stylesheets = [ + { + "name": "styles.css" + }, + { + "name": "carousel.css" + }, + { + "name": "fonts.css" + } + ]; + + vm.macros = [ + { + "name": "Macro 1" + }, + { + "name": "Macro 2" + }, + { + "name": "Macro 3" + } + ]; + + vm.languages = [ + { + "name": "English (United States)" + }, + { + "name": "Danish" + }, + { + "name": "Spanish" + } + ]; + + vm.dictionaryItems = [ + { + "name": "Item 1" + }, + { + "name": "Item 2" + }, + { + "name": "Item 3" + } + ]; + + vm.dataTypes = [ + { + "name": "Datatype 1" + }, + { + "name": "Datatype 2" + }, + { + "name": "Datatype 3" + } + ]; + } + + function back() { + $location.path("packages/packages/overview"); + } + + function createPackage() { + console.log("create package"); + } + + function save() { + console.log("save package"); + } + + onInit(); + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.EditController", EditController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html new file mode 100644 index 0000000000..68e2a30b99 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -0,0 +1,227 @@ +
+ +
+ + + + + + + + + + +
+ +
+
Package Properties
+   +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
Package Content
+   +
+ +
+ + + + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ +
+ +
+ +
+ +
+
Package Files
+   +
+ +
+ + + + + + + +
+ +
+ +
+
+
Package Actions
+   +
+
+ +
+ Documentation +
+ +
+
+
+
+
+ +
+ + + + + + + + + + + + +
+ +
+ +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index 42fcddaa56..43a9d0473e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -44,6 +44,12 @@ "view": "views/packages/views/install-local.html", "active": installPackageUri === "local", "alias": "umbInstallLocal" + }, + { + "name": "Created", + "icon": "icon-add", + "view": "views/packages/views/created.html", + "alias": "umbCreatedPackages" } ]; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js new file mode 100644 index 0000000000..8c92f3553c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js @@ -0,0 +1,84 @@ +(function () { + "use strict"; + + function CreatedController($timeout, $location, localizationService, overlayService) { + + const vm = this; + + vm.deleteCreatedPackage = deleteCreatedPackage; + vm.goToPackage = goToPackage; + vm.createPackage = createPackage; + + function onInit() { + + vm.createdPackages = []; + + //load created packages + $timeout(function(){ + vm.createdPackages = [ + { + "author": "Test", + "files": [], + "iconUrl": "", + "id": 1, + "license": "MIT License", + "licenseUrl": "http://opensource.org/licenses/MIT", + "name": "Test v8", + "url": "https://test.com", + "version": "0.0.0" + }, + { + "author": "Test", + "files": [], + "iconUrl": "", + "id": 2, + "license": "MIT License", + "licenseUrl": "http://opensource.org/licenses/MIT", + "name": "Another Test v8", + "url": "https://test.com", + "version": "0.0.0" + } + ]; + }, 1000); + + } + + function deleteCreatedPackage(createdPackage) { + + const dialog = { + submitButtonLabelKey: "contentTypeEditor_yesDelete", + submit: function (model) { + performDelete(createdPackage); + overlayService.close(); + }, + close: function () { + overlayService.close(); + } + }; + + localizationService.localize("general_delete").then(value => { + dialog.title = value; + overlayService.open(dialog); + }); + + } + + function performDelete(createdPackage) { + console.log("perform delete"); + } + + function goToPackage(createdPackage) { + $location.path("packages/packages/edit/" + createdPackage.id); + } + + function createPackage() { + console.log("create package"); + } + + onInit(); + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.CreatedController", CreatedController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html new file mode 100644 index 0000000000..52f0cef9fd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html @@ -0,0 +1,45 @@ +
+ + + + + + + + + + + + + + + + + +
+
+ + +
+
+
{{ createdPackage.name }}
+
+ {{ createdPackage.version }} | {{ createdPackage.url }}| {{ createdPackage.author }} +
+
+
+ + +
+ +
\ No newline at end of file From bd505a857446dacb7b7f5c9ad717bf70c5684aee Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Dec 2018 13:37:01 +0100 Subject: [PATCH 008/223] get doctypes, datatypes, languages etc from the server and bind selection to model + add content picker --- .../src/views/packages/edit.controller.js | 151 ++++++------------ .../src/views/packages/edit.html | 66 ++++++-- 2 files changed, 102 insertions(+), 115 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index a031baa26d..a161040c24 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($location) { + function EditController($location, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { const vm = this; @@ -16,6 +16,8 @@ vm.back = back; vm.createPackage = createPackage; vm.save = save; + vm.removeContentItem = removeContentItem; + vm.openContentPicker = openContentPicker; function onInit() { // load package @@ -24,113 +26,39 @@ "name": "My package" }; - vm.documentTypes = [ - { - "name": "Home" - }, - { - "name": "Blog" - }, - { - "name": "Blog Post" - }, - { - "name": "News" - }, - { - "name": "News Item" - }, - { - "name": "Contact" - }, - { - "name": "About" - } - ]; + // get all doc types + contentTypeResource.getAll().then(documentTypes => { + vm.documentTypes = documentTypes; + }); - vm.templates = [ - { - "name": "Home" - }, - { - "name": "Blog" - }, - { - "name": "Blog Post" - }, - { - "name": "News" - }, - { - "name": "News Item" - }, - { - "name": "Contact" - }, - { - "name": "About" - } - ]; + // get all templates + templateResource.getAll().then(templates => { + vm.templates = templates; + }); - vm.stylesheets = [ - { - "name": "styles.css" - }, - { - "name": "carousel.css" - }, - { - "name": "fonts.css" - } - ]; + // get all stylesheets + stylesheetResource.getAll().then(stylesheets => { + vm.stylesheets = stylesheets; + }); - vm.macros = [ - { - "name": "Macro 1" - }, - { - "name": "Macro 2" - }, - { - "name": "Macro 3" - } - ]; + // TODO: implement macros + vm.macros = []; + + // get all languages + languageResource.getAll().then(languages => { + vm.languages = languages; + }); - vm.languages = [ - { - "name": "English (United States)" - }, - { - "name": "Danish" - }, - { - "name": "Spanish" - } - ]; + // get all dictionary items + dictionaryResource.getList().then(dictionaryItems => { + vm.dictionaryItems = dictionaryItems; + }); - vm.dictionaryItems = [ - { - "name": "Item 1" - }, - { - "name": "Item 2" - }, - { - "name": "Item 3" - } - ]; + // get all data types items + dataTypeResource.getAll().then(dataTypes => { + vm.dataTypes = dataTypes; + }); - vm.dataTypes = [ - { - "name": "Datatype 1" - }, - { - "name": "Datatype 2" - }, - { - "name": "Datatype 3" - } - ]; } function back() { @@ -145,6 +73,25 @@ console.log("save package"); } + function removeContentItem() { + vm.package.contentItem = null; + } + + function openContentPicker() { + const contentPicker = { + submit: function(model) { + if(model.selection && model.selection.length > 0) { + vm.package.contentItem = model.selection[0]; + } + editorService.close(); + }, + close: function() { + editorService.close(); + } + }; + editorService.contentPicker(contentPicker); + } + onInit(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 68e2a30b99..1888c5d9c1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -78,13 +78,43 @@
- + + + + + + + + Add + + + +
@@ -93,7 +123,10 @@
@@ -102,25 +135,26 @@
-
- -
+ NOT IMPLEMENTED
@@ -129,7 +163,10 @@
@@ -138,7 +175,10 @@
From e599685684b86f2e2b2b75f001e727b485b44a5f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Dec 2018 14:20:34 +0100 Subject: [PATCH 009/223] wip file pickers ui --- .../src/views/packages/edit.controller.js | 17 +++++++++++++++++ .../src/views/packages/edit.html | 17 +++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index a161040c24..c8d6af5d6b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -18,6 +18,7 @@ vm.save = save; vm.removeContentItem = removeContentItem; vm.openContentPicker = openContentPicker; + vm.openFilePicker = openFilePicker; function onInit() { // load package @@ -92,6 +93,22 @@ editorService.contentPicker(contentPicker); } + function openFilePicker() { + const filePicker = { + treeAlias: "files", + section:"settings", + entityType: "file", + submit: function(model) { + console.log(model.selection); + editorService.close(); + }, + close: function() { + editorService.close(); + } + }; + editorService.contentPicker(filePicker); + } + onInit(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 1888c5d9c1..a84d21d709 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -202,12 +202,25 @@ - + + Add + + - + + + + Add +
From d77796bcacfe4ce2e014b3929cd8d5b50f458454 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Dec 2018 15:06:50 +0100 Subject: [PATCH 010/223] show selected files and control --- .../src/views/packages/edit.controller.js | 38 +++++++++++++++++++ .../src/views/packages/edit.html | 24 +++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index c8d6af5d6b..dfc0350630 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -19,6 +19,9 @@ vm.removeContentItem = removeContentItem; vm.openContentPicker = openContentPicker; vm.openFilePicker = openFilePicker; + vm.removeFile = removeFile; + vm.openControlPicker = openControlPicker; + vm.removeControl = removeControl; function onInit() { // load package @@ -98,8 +101,17 @@ treeAlias: "files", section:"settings", entityType: "file", + multiPicker: true, submit: function(model) { console.log(model.selection); + + if(model && model.selection) { + vm.package.files = vm.package.files ? vm.package.files : []; + model.selection.forEach(selected => { + vm.package.files.push(selected); + }); + } + editorService.close(); }, close: function() { @@ -109,6 +121,32 @@ editorService.contentPicker(filePicker); } + function removeFile(index) { + vm.package.files.splice(index, 1); + } + + function openControlPicker() { + const controlPicker = { + treeAlias: "files", + section:"settings", + entityType: "file", + submit: function(model) { + if(model.selection && model.selection.length > 0) { + vm.package.control = model.selection[0]; + } + editorService.close(); + }, + close: function() { + editorService.close(); + } + }; + editorService.contentPicker(controlPicker); + } + + function removeControl() { + vm.package.control = null; + } + onInit(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index a84d21d709..d6309d812a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -202,25 +202,47 @@ + + + + Add + + + Add +
From 00428ec2de547c6bd1abadcb67f4d32f3e31ed2f Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 5 Dec 2018 14:28:07 +0000 Subject: [PATCH 011/223] Adds in new hidden aka initialized=false tree (so that it can be displayed only as a dialog/infinite editor) to display files & folders from root of the site for the package creator UI --- .../src/views/packages/edit.controller.js | 7 +++--- src/Umbraco.Web.UI/config/trees.config | 2 ++ src/Umbraco.Web/Trees/FilesTreeController.cs | 23 +++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Web/Trees/FilesTreeController.cs diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index c8d6af5d6b..ffdeee88bd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -44,7 +44,7 @@ // TODO: implement macros vm.macros = []; - + // get all languages languageResource.getAll().then(languages => { vm.languages = languages; @@ -95,9 +95,10 @@ function openFilePicker() { const filePicker = { + section: "settings", treeAlias: "files", - section:"settings", entityType: "file", + onlyInitialized: false, submit: function(model) { console.log(model.selection); editorService.close(); @@ -106,7 +107,7 @@ editorService.close(); } }; - editorService.contentPicker(filePicker); + editorService.treePicker(filePicker); } onInit(); diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config index 2b99f8751f..da6f75300a 100644 --- a/src/Umbraco.Web.UI/config/trees.config +++ b/src/Umbraco.Web.UI/config/trees.config @@ -20,6 +20,8 @@ + + diff --git a/src/Umbraco.Web/Trees/FilesTreeController.cs b/src/Umbraco.Web/Trees/FilesTreeController.cs new file mode 100644 index 0000000000..a435d3a668 --- /dev/null +++ b/src/Umbraco.Web/Trees/FilesTreeController.cs @@ -0,0 +1,23 @@ +using Umbraco.Core; +using Umbraco.Core.IO; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] + [Tree(Constants.Applications.Settings, "files", "Files", "icon-folder", "icon-folder", sortOrder: 13, initialize: false)] + public class FilesTreeController : FileSystemTreeController + { + protected override IFileSystem FileSystem => new PhysicalFileSystem("~/"); // fixme inject + + protected override string[] Extensions => new string[] { }; + + protected override string FileIcon => "icon-script"; + + protected override void OnRenderFolderNode(ref TreeNode treeNode) + { + //TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now. + treeNode.AdditionalData["jsClickCallback"] = "javascript:void(0);"; + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 32134e7a45..717c2f508e 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -183,6 +183,7 @@ + From 749a25aabbb25fd497759a92c05228d7891a99ae Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Dec 2018 15:41:55 +0100 Subject: [PATCH 012/223] user overlayService for ysods --- .../src/common/services/events.service.js | 1 - .../common/services/umbrequesthelper.service.js | 16 +++++----------- .../src/controllers/main.controller.js | 8 -------- src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml | 6 ------ 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/events.service.js b/src/Umbraco.Web.UI.Client/src/common/services/events.service.js index 6bab8fda81..51f63e6787 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/events.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/events.service.js @@ -6,7 +6,6 @@ app.ready app.authenticated app.notAuthenticated - app.ysod app.reInitialize app.userRefresh app.navigationReady diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index fcb5585d5d..0834799be4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -3,7 +3,7 @@ * @name umbraco.services.umbRequestHelper * @description A helper object used for sending requests to the server **/ -function umbRequestHelper($http, $q, notificationsService, eventsService, formHelper) { +function umbRequestHelper($http, $q, notificationsService, eventsService, formHelper, overlayService) { return { @@ -176,11 +176,8 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe //show a ysod dialog if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { - eventsService.emit('app.ysod', - { - errorMsg: 'An error occured', - data: response.data - }); + const error = { errorMsg: 'An error occured', data: response.data }; + overlayService.ysod(error); } else { //show a simple error notification @@ -290,11 +287,8 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe } else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { //show a ysod dialog - eventsService.emit('app.ysod', - { - errorMsg: 'An error occured', - data: response.data - }); + const error = { errorMsg: 'An error occured', data: response.data }; + overlayService.ysod(error); } else { //show a simple error notification diff --git a/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js index 30a7e2ac7d..c2b2ba26d7 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js @@ -103,14 +103,6 @@ function MainController($scope, $location, appState, treeService, notificationsS })); - evts.push(eventsService.on("app.ysod", function (name, error) { - $scope.ysodOverlay = { - view: "ysod", - error: error, - show: true - }; - })); - // events for search evts.push(eventsService.on("appState.searchState.changed", function (e, args) { if (args.key === "show") { diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml index 4659674c59..2ee71a6555 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml @@ -106,12 +106,6 @@ parent-scope="overlay.parentScope"> - - - From 74d9945e09e49a5ee7fc9755cf955a283ce3a156 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Dec 2018 15:42:44 +0100 Subject: [PATCH 013/223] Add title to files and control pickers --- src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 8b1878d6fc..ff587dd540 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -98,6 +98,7 @@ function openFilePicker() { const filePicker = { + title: "Select files", section: "settings", treeAlias: "files", entityType: "file", @@ -128,6 +129,7 @@ function openControlPicker() { const controlPicker = { + title: "Select control", treeAlias: "files", section:"settings", entityType: "file", From 8425c3124d9771d0b8b48b4acaaa9a132f592feb Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 5 Dec 2018 15:15:45 +0000 Subject: [PATCH 014/223] Modify FileSystemTree Controller - that if * is used for file extension then we will return all files :) --- src/Umbraco.Web/Trees/FileSystemTreeController.cs | 4 ++++ src/Umbraco.Web/Trees/FilesTreeController.cs | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Trees/FileSystemTreeController.cs b/src/Umbraco.Web/Trees/FileSystemTreeController.cs index 9babb656fe..bf301ebe60 100644 --- a/src/Umbraco.Web/Trees/FileSystemTreeController.cs +++ b/src/Umbraco.Web/Trees/FileSystemTreeController.cs @@ -57,6 +57,10 @@ namespace Umbraco.Web.Trees var files = FileSystem.GetFiles(path).Where(x => { var extension = Path.GetExtension(x); + + if (Extensions.Contains("*")) + return true; + return extension != null && Extensions.Contains(extension.Trim('.'), StringComparer.InvariantCultureIgnoreCase); }); diff --git a/src/Umbraco.Web/Trees/FilesTreeController.cs b/src/Umbraco.Web/Trees/FilesTreeController.cs index a435d3a668..947522747d 100644 --- a/src/Umbraco.Web/Trees/FilesTreeController.cs +++ b/src/Umbraco.Web/Trees/FilesTreeController.cs @@ -10,9 +10,11 @@ namespace Umbraco.Web.Trees { protected override IFileSystem FileSystem => new PhysicalFileSystem("~/"); // fixme inject - protected override string[] Extensions => new string[] { }; + private static readonly string[] ExtensionsStatic = { "*" }; - protected override string FileIcon => "icon-script"; + protected override string[] Extensions => ExtensionsStatic; + + protected override string FileIcon => "icon-document"; protected override void OnRenderFolderNode(ref TreeNode treeNode) { From 849cc2d383cefa9cbc08551e2e0a7f71b5ddaffc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 10:20:48 +0100 Subject: [PATCH 015/223] remove tree sync for packages and users as we don't have a tree --- .../src/views/packages/overview.controller.js | 3 --- .../src/views/users/overview.controller.js | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index 43a9d0473e..418861c636 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -53,9 +53,6 @@ } ]; - $timeout(function () { - navigationService.syncTree({ tree: "packages", path: "-1" }); - }); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js index 4d25419175..49e8007d8c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js @@ -25,10 +25,6 @@ setPageName(); - $timeout(function () { - navigationService.syncTree({ tree: "users", path: "-1" }); - }); - } function loadNavigation() { From 3546de32077f9d62c923f4737d9cfdbee5e228c8 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 09:32:04 +0000 Subject: [PATCH 016/223] Update packages tree so that its a full screen app/section like users --- src/Umbraco.Web.UI/config/trees.config | 2 +- .../Trees/PackagesTreeController.cs | 86 +++---------------- src/Umbraco.Web/Trees/UserTreeController.cs | 2 - 3 files changed, 13 insertions(+), 77 deletions(-) diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config index da6f75300a..dd9fac783f 100644 --- a/src/Umbraco.Web.UI/config/trees.config +++ b/src/Umbraco.Web.UI/config/trees.config @@ -23,7 +23,7 @@ - + diff --git a/src/Umbraco.Web/Trees/PackagesTreeController.cs b/src/Umbraco.Web/Trees/PackagesTreeController.cs index 8158b47985..b8acb98daa 100644 --- a/src/Umbraco.Web/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/PackagesTreeController.cs @@ -1,21 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http.Formatting; +using System.Net.Http.Formatting; using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi.Filters; -using umbraco; -using umbraco.cms.businesslogic.packager; -using Umbraco.Core.Services; -using Umbraco.Web.Actions; using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Packages)] - [Tree(Constants.Applications.Packages, Constants.Trees.Packages, null, sortOrder: 0)] + [Tree(Constants.Applications.Packages, Constants.Trees.Packages, null, sortOrder: 0, isSingleNodeTree: true)] [PluginController("UmbracoTrees")] [CoreTree] public class PackagesTreeController : TreeController @@ -27,80 +20,25 @@ namespace Umbraco.Web.Trees protected override TreeNode CreateRootNode(FormDataCollection queryStrings) { var root = base.CreateRootNode(queryStrings); - - root.RoutePath = $"{Constants.Applications.Packages}/{Constants.Trees.Packages}/overview"; - + + //this will load in a custom UI instead of the dashboard for the root node + root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Packages, Constants.Trees.Packages, "overview"); root.Icon = "icon-box"; - + + root.HasChildren = false; return root; } + protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) { - var nodes = new TreeNodeCollection(); - - var createdPackages = CreatedPackage.GetAllCreatedPackages(); - - if (id == "created") - { - nodes.AddRange( - createdPackages - .OrderBy(entity => entity.Data.Name) - .Select(dt => - { - var node = CreateTreeNode(dt.Data.Id.ToString(), id, queryStrings, dt.Data.Name, "icon-inbox", false, - $"/{queryStrings.GetValue("application")}/framed/{Uri.EscapeDataString("developer/Packages/EditPackage.aspx?id=" + dt.Data.Id)}"); - return node; - })); - } - else - { - //must be root - var node = CreateTreeNode( - "created", - id, - queryStrings, - Services.TextService.Localize("treeHeaders/createdPackages"), - "icon-folder", - createdPackages.Count > 0, - string.Empty); - - - - //TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now. - node.AdditionalData["jsClickCallback"] = "javascript:void(0);"; - - nodes.Add(node); - } - - - - return nodes; + //full screen app without tree nodes + return TreeNodeCollection.Empty; } protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) { - var menu = new MenuItemCollection(); - - // Root actions - if (id == "-1") - { - menu.Items.Add(Services.TextService, opensDialog: true) - .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); - } - else if (id == "created") - { - menu.Items.Add(Services.TextService, opensDialog: true) - .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); - - menu.Items.Add(new RefreshNode(Services.TextService, true)); - } - else - { - //it's a package node - menu.Items.Add(Services.TextService, opensDialog: true); - } - - return menu; + //doesn't have a menu, this is a full screen app without tree nodes + return MenuItemCollection.Empty; } } } diff --git a/src/Umbraco.Web/Trees/UserTreeController.cs b/src/Umbraco.Web/Trees/UserTreeController.cs index f029a929de..57f5913fbb 100644 --- a/src/Umbraco.Web/Trees/UserTreeController.cs +++ b/src/Umbraco.Web/Trees/UserTreeController.cs @@ -1,6 +1,4 @@ using System.Net.Http.Formatting; -using Umbraco.Core; -using Umbraco.Core.Services; using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi.Filters; From 17d489bb54dcbdd755dc15376662ae3b2872f02c Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 09:50:05 +0000 Subject: [PATCH 017/223] Adds new API/Editor endpoint to deal with created packages - get methods --- src/Umbraco.Web/Editors/PackageController.cs | 49 ++++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 2 files changed, 50 insertions(+) create mode 100644 src/Umbraco.Web/Editors/PackageController.cs diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs new file mode 100644 index 0000000000..e6d84e8288 --- /dev/null +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using umbraco.cms.businesslogic.packager; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi.Filters; + +namespace Umbraco.Web.Editors +{ + /// + /// A controller used for installing packages and managing all of the data in the packages section in the back office + /// + [PluginController("UmbracoApi")] + [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] + public class PackageController : UmbracoAuthorizedJsonController + { + [HttpGet] + public List GetCreatedPackages() + { + //TODO: Packager stuff still lives in business logic - YUK + //TODO: Could be too much data down the wire + return CreatedPackage.GetAllCreatedPackages(); + + /* + * "author": "Test", + "files": [], + "iconUrl": "", + "id": 1, + "license": "MIT License", + "licenseUrl": "http://opensource.org/licenses/MIT", + "name": "Test v8", + "url": "https://test.com", + "version": "0.0.0" + */ + + + } + + [HttpGet] + public CreatedPackage GetCreatedPackageById(int id) + { + return CreatedPackage.GetById(id); + } + + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 717c2f508e..5b396c9486 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -111,6 +111,7 @@ + From 9df8c71bf4a06e944738ff4998e64727e60ecb78 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 09:54:21 +0000 Subject: [PATCH 018/223] Adds in Delete method --- src/Umbraco.Web/Editors/PackageController.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index e6d84e8288..6d4655f0be 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; using System.Web.Http; using umbraco.cms.businesslogic.packager; using Umbraco.Web.Mvc; @@ -45,5 +43,15 @@ namespace Umbraco.Web.Editors return CreatedPackage.GetById(id); } + [HttpDelete] + public HttpResponseMessage DeleteCreatedPackageById(int id) + { + var package = CreatedPackage.GetById(id); + package.Delete(); + + //204 No Content + return new HttpResponseMessage(HttpStatusCode.NoContent); + } + } } From cd8bb8ed99cdcee645e4c23061cf12592407b2b7 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 10:07:53 +0000 Subject: [PATCH 019/223] Adds the package api controller to Umbraco.Sys JS object --- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 23d8e2cc4e..472728e087 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -208,6 +208,10 @@ namespace Umbraco.Web.Editors "packageInstallApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.Fetch(string.Empty)) }, + { + "packageApiBaseUrl ", _urlHelper.GetUmbracoApiServiceBaseUrl( + controller => controller.GetCreatedPackages()) + }, { "relationApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetById(0)) From de86dace707cbab5c8b32c45cb23e59f54c2695b Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 10:18:31 +0000 Subject: [PATCH 020/223] Adds a Create/Publish method - will need to figure out validation --- src/Umbraco.Web/Editors/PackageController.cs | 34 +++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 6d4655f0be..d192ee21f3 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -8,6 +8,8 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { + //TODO: Packager stuff still lives in business logic - YUK + /// /// A controller used for installing packages and managing all of the data in the packages section in the back office /// @@ -18,23 +20,8 @@ namespace Umbraco.Web.Editors [HttpGet] public List GetCreatedPackages() { - //TODO: Packager stuff still lives in business logic - YUK //TODO: Could be too much data down the wire return CreatedPackage.GetAllCreatedPackages(); - - /* - * "author": "Test", - "files": [], - "iconUrl": "", - "id": 1, - "license": "MIT License", - "licenseUrl": "http://opensource.org/licenses/MIT", - "name": "Test v8", - "url": "https://test.com", - "version": "0.0.0" - */ - - } [HttpGet] @@ -43,6 +30,23 @@ namespace Umbraco.Web.Editors return CreatedPackage.GetById(id); } + [HttpPost] + public CreatedPackage PostCreatePackage(PackageInstance model) + { + //TODO Validation on the model?! + var newPackage = new CreatedPackage + { + Data = model + }; + + //Save then publish + newPackage.Save(); + newPackage.Publish(); + + //We should have packagepath populated now + return newPackage; + } + [HttpDelete] public HttpResponseMessage DeleteCreatedPackageById(int id) { From 68006f78ee6ebf184a80d1719630a151aa344517 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 11:33:03 +0100 Subject: [PATCH 021/223] wire up end point for get created packages --- .../src/common/resources/package.resource.js | 18 ++++++++++ .../src/views/packages/edit.controller.js | 21 ++++++++--- .../packages/views/created.controller.js | 35 ++++--------------- .../src/views/packages/views/created.html | 6 ++++ 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 8fd6836884..522423f5b2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -151,7 +151,25 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { "packageInstallApiBaseUrl", "CleanUp"), umbPackage), 'Failed to install package. Error during the step "CleanUp" '); + }, + + /** + * @ngdoc method + * @name umbraco.resources.packageInstallResource#getCreated + * @methodOf umbraco.resources.packageInstallResource + * + * @description + * Gets a list of created packages + */ + getAllCreated: function() { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "GetCreated")), + 'Failed to get created packages'); } + }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index ff587dd540..af17c44b60 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($location, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { + function EditController($location, $routeParams, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { const vm = this; @@ -24,11 +24,22 @@ vm.removeControl = removeControl; function onInit() { - // load package - vm.package = { - "name": "My package" - }; + const packageId = $routeParams.id; + const create = $routeParams.create; + + if(create) { + //pre populate package with some values + vm.package = { + "version": "1.0.0", + "license": "MIT License", + "licenseUrl": "http://opensource.org/licenses/MIT" + }; + + } else { + // load package + + } // get all doc types contentTypeResource.getAll().then(documentTypes => { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js index 8c92f3553c..2a10a9e8fe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function CreatedController($timeout, $location, localizationService, overlayService) { + function CreatedController($timeout, $location, packageResource, localizationService, overlayService) { const vm = this; @@ -13,33 +13,9 @@ vm.createdPackages = []; - //load created packages - $timeout(function(){ - vm.createdPackages = [ - { - "author": "Test", - "files": [], - "iconUrl": "", - "id": 1, - "license": "MIT License", - "licenseUrl": "http://opensource.org/licenses/MIT", - "name": "Test v8", - "url": "https://test.com", - "version": "0.0.0" - }, - { - "author": "Test", - "files": [], - "iconUrl": "", - "id": 2, - "license": "MIT License", - "licenseUrl": "http://opensource.org/licenses/MIT", - "name": "Another Test v8", - "url": "https://test.com", - "version": "0.0.0" - } - ]; - }, 1000); + packageResource.getAllCreated().then(createdPackages => { + vm.createdPackages = createdPackages; + }, angular.noop); } @@ -72,7 +48,8 @@ } function createPackage() { - console.log("create package"); + $location.search('create', null); + $location.path("packages/packages/edit/-1").search("create", "true"); } onInit(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html index 52f0cef9fd..53fd78b3c6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html @@ -42,4 +42,10 @@ + + No packages have been created yet + +
\ No newline at end of file From 17a005c1635f1fc9afe698c3b312a2945ed3a788 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 10:42:05 +0000 Subject: [PATCH 022/223] Fix up Umbraco.Sys object URL to API endpoint --- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 472728e087..86c232c449 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -209,7 +209,7 @@ namespace Umbraco.Web.Editors controller => controller.Fetch(string.Empty)) }, { - "packageApiBaseUrl ", _urlHelper.GetUmbracoApiServiceBaseUrl( + "packageApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetCreatedPackages()) }, { From 452f97de625bddda1194511e17bb3e9783c3e98e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 11:53:26 +0100 Subject: [PATCH 023/223] wire up get created package by id --- .../src/common/resources/package.resource.js | 20 ++++++++++++++++++- .../src/views/packages/edit.controller.js | 7 ++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 522423f5b2..6023a16d5b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -166,8 +166,26 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { $http.get( umbRequestHelper.getApiUrl( "packageApiBaseUrl", - "GetCreated")), + "GetCreatedPackages")), 'Failed to get created packages'); + }, + + /** + * @ngdoc method + * @name umbraco.resources.packageInstallResource#getCreatedById + * @methodOf umbraco.resources.packageInstallResource + * + * @description + * Gets a created package by id + */ + getCreatedById: function(id) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "GetCreatedPackageById", + [{ id: id }])), + 'Failed to get package'); } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index af17c44b60..a3408e1360 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($location, $routeParams, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { + function EditController($location, $routeParams, packageResource, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { const vm = this; @@ -35,10 +35,11 @@ "license": "MIT License", "licenseUrl": "http://opensource.org/licenses/MIT" }; - } else { // load package - + packageResource.getCreatedById(packageId).then(createdPackage => { + vm.package = createdPackage; + }, angular.noop); } // get all doc types From c7e6cf44ed019e4e99c493c786e02e7b4c079301 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 11:21:01 +0000 Subject: [PATCH 024/223] Anotate model so its camelCase friendly for API responses for Mads --- .../PackageInstance/PackageInstance.cs | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs index 8f7cb56320..63bd568b73 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs @@ -1,70 +1,97 @@ using System; - -using System.Xml; -using System.Xml.XPath; using System.Collections.Generic; +using System.Runtime.Serialization; namespace umbraco.cms.businesslogic.packager { + [DataContract(Name = "packageInstance")] public class PackageInstance { + [DataMember(Name = "id")] public int Id { get; set; } + [DataMember(Name = "repositoryGuid")] public string RepositoryGuid { get; set; } + [DataMember(Name = "packageGuid")] public string PackageGuid { get; set; } + [DataMember(Name = "hasUpdate")] public bool HasUpdate { get; set; } + [DataMember(Name = "name")] public string Name { get; set; } + [DataMember(Name = "url")] public string Url { get; set; } + [DataMember(Name = "folder")] public string Folder { get; set; } + [DataMember(Name = "packagePath")] public string PackagePath { get; set; } + [DataMember(Name = "version")] public string Version { get; set; } /// /// The minimum umbraco version that this package requires /// + [DataMember(Name = "umbracoVersion")] public Version UmbracoVersion { get; set; } + [DataMember(Name = "author")] public string Author { get; set; } + [DataMember(Name = "authorUrl")] public string AuthorUrl { get; set; } + [DataMember(Name = "license")] public string License { get; set; } + [DataMember(Name = "licenseUrl")] public string LicenseUrl { get; set; } + [DataMember(Name = "readme")] public string Readme { get; set; } + [DataMember(Name = "contentLoadChildNodes")] public bool ContentLoadChildNodes { get; set; } + [DataMember(Name = "contentNodeId")] public string ContentNodeId { get; set; } + [DataMember(Name = "macros")] public List Macros { get; set; } + [DataMember(Name = "languages")] public List Languages { get; set; } + [DataMember(Name = "dictionaryItems")] public List DictionaryItems { get; set; } + [DataMember(Name = "templates")] public List Templates { get; set; } + [DataMember(Name = "documenttypes")] public List Documenttypes { get; set; } + [DataMember(Name = "stylesheets")] public List Stylesheets { get; set; } + [DataMember(Name = "files")] public List Files { get; set; } + [DataMember(Name = "loadControl")] public string LoadControl { get; set; } + [DataMember(Name = "actions")] public string Actions { get; set; } + [DataMember(Name = "dataTypes")] public List DataTypes { get; set; } + [DataMember(Name = "iconUrl")] public string IconUrl { get; set; } public PackageInstance() From 465229fb39f4f49deb56f5eaec9822fcfb8f1553 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 11:21:28 +0000 Subject: [PATCH 025/223] Return PackageInstance as opposed to CreatedPackage in API responses --- src/Umbraco.Web/Editors/PackageController.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index d192ee21f3..652a7c29f8 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; @@ -18,20 +19,21 @@ namespace Umbraco.Web.Editors public class PackageController : UmbracoAuthorizedJsonController { [HttpGet] - public List GetCreatedPackages() + public List GetCreatedPackages() { //TODO: Could be too much data down the wire - return CreatedPackage.GetAllCreatedPackages(); + return CreatedPackage.GetAllCreatedPackages().Select(x => x.Data).ToList(); } [HttpGet] - public CreatedPackage GetCreatedPackageById(int id) + public PackageInstance GetCreatedPackageById(int id) { - return CreatedPackage.GetById(id); + //TODO throw an error if cant find by ID + return CreatedPackage.GetById(id).Data; } [HttpPost] - public CreatedPackage PostCreatePackage(PackageInstance model) + public PackageInstance PostCreatePackage(PackageInstance model) { //TODO Validation on the model?! var newPackage = new CreatedPackage @@ -42,14 +44,15 @@ namespace Umbraco.Web.Editors //Save then publish newPackage.Save(); newPackage.Publish(); - + //We should have packagepath populated now - return newPackage; + return newPackage.Data; } [HttpDelete] public HttpResponseMessage DeleteCreatedPackageById(int id) { + //TODO: Validation ensure can find it by ID var package = CreatedPackage.GetById(id); package.Delete(); From 3c399ade16d9d4481d8671bee094e8baf20a7273 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 12:50:08 +0100 Subject: [PATCH 026/223] last textarea should be actions --- src/Umbraco.Web.UI.Client/src/views/packages/edit.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index d6309d812a..a6ef4093a7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -255,13 +255,13 @@
From 7df08696493461a0f12b33ee4c373e961d507bbb Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 13:13:55 +0100 Subject: [PATCH 027/223] wire up delete --- .../packages/views/created.controller.js | 23 ++++++++++++++----- .../src/views/packages/views/created.html | 2 +- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js index 2a10a9e8fe..9d06ea1092 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.controller.js @@ -19,28 +19,39 @@ } - function deleteCreatedPackage(createdPackage) { + function deleteCreatedPackage(event, index, createdPackage) { + + event.stopPropagation(); + event.preventDefault(); const dialog = { submitButtonLabelKey: "contentTypeEditor_yesDelete", submit: function (model) { - performDelete(createdPackage); + performDelete(index, createdPackage); overlayService.close(); }, close: function () { overlayService.close(); } }; + + const keys = [ + "general_delete", + "defaultdialogs_confirmdelete" + ]; - localizationService.localize("general_delete").then(value => { - dialog.title = value; + localizationService.localizeMany(keys).then(values => { + dialog.title = values[0]; + dialog.content = values[1]; overlayService.open(dialog); }); } - function performDelete(createdPackage) { - console.log("perform delete"); + function performDelete(index, createdPackage) { + packageResource.deleteCreatedPackage(createdPackage.id).then(()=> { + vm.createdPackages.splice(index, 1); + }, angular.noop); } function goToPackage(createdPackage) { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html index 53fd78b3c6..632d2e2b3c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/created.html @@ -35,7 +35,7 @@ size="xxs" label-key="general_delete" add-ellipsis="true" - action="vm.deleteCreatedPackage(createdPackage)"> + action="vm.deleteCreatedPackage($event, $index, createdPackage)"> From 9409b46ef41774b1107103bc5b56360bbb8ec9a4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 13:57:21 +0100 Subject: [PATCH 028/223] fix back buttons --- .../src/views/packages/overview.controller.js | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index 418861c636..4ca0015aa5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -10,6 +10,8 @@ // we will refresh and then navigate there. var installPackageUri = localStorageService.get("packageInstallUri"); + const packageUri = $location.search().subview; + if (installPackageUri) { localStorageService.remove("packageInstallUri"); } @@ -28,28 +30,41 @@ "name": "Packages", "icon": "icon-cloud", "view": "views/packages/views/repo.html", - "active": !installPackageUri || installPackageUri === "navigation", - "alias": "umbPackages" + "active": !packageUri || installPackageUri === "navigation" || packageUri === "navigation", + "alias": "umbPackages", + "action": function() { + $location.search("subview", "navigation"); + } }, { "name": "Installed", "icon": "icon-box", "view": "views/packages/views/installed.html", - "active": installPackageUri === "installed", - "alias": "umbInstalled" + "active": installPackageUri === "installed" || packageUri === "installed", + "alias": "umbInstalled", + "action": function() { + $location.search("subview", "installed"); + } }, { "name": "Install local", "icon": "icon-add", "view": "views/packages/views/install-local.html", - "active": installPackageUri === "local", - "alias": "umbInstallLocal" + "active": installPackageUri === "local" || packageUri === "local", + "alias": "umbInstallLocal", + "action": function() { + $location.search("subview", "local"); + } }, { "name": "Created", "icon": "icon-add", "view": "views/packages/views/created.html", - "alias": "umbCreatedPackages" + "active": packageUri === "created", + "alias": "umbCreatedPackages", + "action": function() { + $location.search("subview", "created"); + } } ]; From 34dc81058a813115c5d74f07b4c5ae599d88b30c Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 13:09:34 +0000 Subject: [PATCH 029/223] Move the Delete method over into our new controller --- src/Umbraco.Web/Editors/PackageController.cs | 19 ++++++++++++------ .../Editors/PackageInstallController.cs | 20 +------------------ .../PackageInstance/PackageInstance.cs | 2 +- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 652a7c29f8..c2a78da1be 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -49,16 +49,23 @@ namespace Umbraco.Web.Editors return newPackage.Data; } + /// + /// Deletes a created package + /// + /// + /// + [HttpPost] [HttpDelete] - public HttpResponseMessage DeleteCreatedPackageById(int id) + public IHttpActionResult DeleteCreatedPackage(int packageId) { - //TODO: Validation ensure can find it by ID - var package = CreatedPackage.GetById(id); + var package = CreatedPackage.GetById(packageId); + if (package == null) + return NotFound(); + package.Delete(); - //204 No Content - return new HttpResponseMessage(HttpStatusCode.NoContent); + return Ok(); } - + } } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 94465feab8..7224ddfb98 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -289,25 +289,7 @@ namespace Umbraco.Web.Editors }) .ToList(); } - - /// - /// Deletes a created package - /// - /// - /// - [HttpPost] - [HttpDelete] - public IHttpActionResult DeleteCreatedPackage(int packageId) - { - var package = CreatedPackage.GetById(packageId); - if (package == null) - return NotFound(); - - package.Delete(); - - return Ok(); - } - + private void PopulateFromPackageData(LocalPackageInstallModel model) { var ins = new global::umbraco.cms.businesslogic.packager.Installer(Security.CurrentUser.Id); diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs index 63bd568b73..68166c9dd5 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs @@ -39,7 +39,7 @@ namespace umbraco.cms.businesslogic.packager /// [DataMember(Name = "umbracoVersion")] public Version UmbracoVersion { get; set; } - + [DataMember(Name = "author")] public string Author { get; set; } From e566e240b13d427d93cb493bcc911e146eb4c61f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 14:49:02 +0100 Subject: [PATCH 030/223] prefill umbraco version number --- .../src/views/packages/edit.controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index a3408e1360..f9eb6f8c84 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -31,9 +31,10 @@ if(create) { //pre populate package with some values vm.package = { - "version": "1.0.0", + "version": "0.0.1", "license": "MIT License", - "licenseUrl": "http://opensource.org/licenses/MIT" + "licenseUrl": "http://opensource.org/licenses/MIT", + "umbracoVersion": Umbraco.Sys.ServerVariables.application.version }; } else { // load package From 6f5155b0f39c53c55c093a2f92364b53cbad0117 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 13:54:38 +0000 Subject: [PATCH 031/223] Adds in new attribute to override the specific PackageController JSON Serializer to use the NewtonSoft built-in VersionConvertor --- src/Umbraco.Web/Editors/PackageController.cs | 3 +++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../WebApi/SerializeVersionAttribute.cs | 15 +++++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 src/Umbraco.Web/WebApi/SerializeVersionAttribute.cs diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index c2a78da1be..baacea53d8 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -2,9 +2,11 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Formatting; using System.Web.Http; using umbraco.cms.businesslogic.packager; using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors @@ -15,6 +17,7 @@ namespace Umbraco.Web.Editors /// A controller used for installing packages and managing all of the data in the packages section in the back office /// [PluginController("UmbracoApi")] + [SerializeVersion] [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageController : UmbracoAuthorizedJsonController { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 5b396c9486..e32d808be9 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -190,6 +190,7 @@ + diff --git a/src/Umbraco.Web/WebApi/SerializeVersionAttribute.cs b/src/Umbraco.Web/WebApi/SerializeVersionAttribute.cs new file mode 100644 index 0000000000..ea285434b3 --- /dev/null +++ b/src/Umbraco.Web/WebApi/SerializeVersionAttribute.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json.Converters; +using System; +using System.Web.Http.Controllers; + +namespace Umbraco.Web.WebApi +{ + internal class SerializeVersionAttribute : Attribute, IControllerConfiguration + { + public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) + { + var formatter = controllerSettings.Formatters.JsonFormatter; + formatter.SerializerSettings.Converters.Add(new VersionConverter()); + } + } +} From 57f462b2046eed5bec1cf531f12ed8cd7964aa98 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Dec 2018 15:26:12 +0100 Subject: [PATCH 032/223] wire up create package --- .../src/common/resources/package.resource.js | 18 +++++++++++++++++- .../src/views/packages/edit.controller.js | 10 +++++++++- .../src/views/packages/edit.html | 16 ++++------------ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 6023a16d5b..28a9f3b9ac 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -186,8 +186,24 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { "GetCreatedPackageById", [{ id: id }])), 'Failed to get package'); + }, + + /** + * @ngdoc method + * @name umbraco.resources.packageInstallResource#createPackage + * @methodOf umbraco.resources.packageInstallResource + * + * @description + * Creates a new package + */ + createPackage: function (umbPackage) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "PostCreatePackage"), umbPackage), + 'Failed to create package'); } - }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index f9eb6f8c84..d5571ba78c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -83,7 +83,15 @@ } function createPackage() { - console.log("create package"); + + vm.createPackageButtonState = "busy"; + + packageResource.createPackage(vm.package).then((updatedPackage) => { + vm.package = updatedPackage; + vm.createPackageButtonState = "success"; + }, function(error){ + vm.createPackageButtonState = "error"; + }); } function save() { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index a6ef4093a7..cc48dddf6f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -47,7 +47,7 @@ - + @@ -268,25 +268,17 @@
+
{{vm.package | json}}
+ - - From 2013fd1619c56be965a0008f8ff5d932e15237a0 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 14:41:53 +0000 Subject: [PATCH 033/223] Try the MakeNew method on CreatedPackage() --- src/Umbraco.Web/Editors/PackageController.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index baacea53d8..3713674f84 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -38,11 +38,11 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstance PostCreatePackage(PackageInstance model) { + + var newPackage = CreatedPackage.MakeNew(model.Name); + newPackage.Data = model; + //TODO Validation on the model?! - var newPackage = new CreatedPackage - { - Data = model - }; //Save then publish newPackage.Save(); From 7f380347dcc0a6047c59827c44f73e3f6e85580b Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 6 Dec 2018 15:35:40 +0000 Subject: [PATCH 034/223] Some WIP binding updates in the view - will mostly need to bind an array of integers back to items --- .../src/views/packages/edit.html | 92 ++++++++++--------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index cc48dddf6f..9ba5421683 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -3,7 +3,7 @@
- + - + @@ -23,7 +23,7 @@
Package Properties
 
- +
@@ -39,7 +39,7 @@ - + @@ -67,22 +67,24 @@
- +
- +
Package Content
 
- +
+ + +
{{vm.documentTypes | json }} 
+
{{vm.templates | json }} 
- + +
{{vm.stylesheets | json }}
- NOT IMPLEMENTED + NOT IMPLEMENTED IN V8 YET +
{{vm.languages | json }}
@@ -254,9 +260,9 @@  
-
Documentation @@ -275,7 +281,7 @@ - - + - +
\ No newline at end of file From 6566a43ef9a26be1901f73b64e05fa8a3608d1dc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Dec 2018 10:05:31 +0100 Subject: [PATCH 035/223] change end point for delete created package --- .../src/common/resources/package.resource.js | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 28a9f3b9ac..0b74729cf6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -33,15 +33,6 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { 'Failed to validate package ' + name); }, - deleteCreatedPackage: function (packageId) { - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "packageInstallApiBaseUrl", - "DeleteCreatedPackage", { packageId: packageId })), - 'Failed to delete package ' + packageId); - }, - uninstall: function(packageId) { return umbRequestHelper.resourcePromise( $http.post( @@ -203,6 +194,23 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { "packageApiBaseUrl", "PostCreatePackage"), umbPackage), 'Failed to create package'); + }, + + /** + * @ngdoc method + * @name umbraco.resources.packageInstallResource#deleteCreatedPackage + * @methodOf umbraco.resources.packageInstallResource + * + * @description + * Detes a created package + */ + deleteCreatedPackage: function (packageId) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "DeleteCreatedPackage", { packageId: packageId })), + 'Failed to delete package ' + packageId); } }; } From fbf29f9f4718f1233939f69dc439962e694505bc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Dec 2018 10:13:55 +0100 Subject: [PATCH 036/223] bind stylesheets correctly --- src/Umbraco.Web.UI.Client/src/views/packages/edit.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 9ba5421683..796edff588 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -143,7 +143,7 @@ + checklist-value="stylesheet.name" /> {{stylesheet.path}}
From a9aba6731dbe41de27475c748b4287ba860efed5 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 7 Dec 2018 09:29:44 +0000 Subject: [PATCH 037/223] Update to CreatePackage API endpoint - the ID & Guid was getting overwritten by mistake --- src/Umbraco.Web/Editors/PackageController.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 3713674f84..a2505a1287 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -38,10 +38,16 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstance PostCreatePackage(PackageInstance model) { - var newPackage = CreatedPackage.MakeNew(model.Name); - newPackage.Data = model; + var packageId = newPackage.Data.Id; + var packageGuid = newPackage.Data.PackageGuid; + //Need to reset the package ID - as the posted model the package ID is always 0 + //MakeNew will init create the XML & update the file and give us an ID to use + newPackage.Data = model; + newPackage.Data.Id = packageId; + newPackage.Data.PackageGuid = packageGuid; + //TODO Validation on the model?! //Save then publish From 5d3432db511af114b05b8dc6ea2dc75f0d62b673 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Dec 2018 11:15:08 +0100 Subject: [PATCH 038/223] get render model for content item --- .../src/views/packages/edit.controller.js | 16 +++++++++++++--- .../src/views/packages/edit.html | 6 ++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index d5571ba78c..6520a2ecf8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($location, $routeParams, packageResource, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { + function EditController($location, $routeParams, entityResource, packageResource, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { const vm = this; @@ -40,6 +40,15 @@ // load package packageResource.getCreatedById(packageId).then(createdPackage => { vm.package = createdPackage; + + // get render model for content node + if(vm.package.contentNodeId) { + entityResource.getById(vm.package.contentNodeId, "Document") + .then((entity) => { + vm.contentNodeDisplayModel = entity; + }); + } + }, angular.noop); } @@ -99,14 +108,15 @@ } function removeContentItem() { - vm.package.contentItem = null; + vm.package.contentNodeId = null; } function openContentPicker() { const contentPicker = { submit: function(model) { if(model.selection && model.selection.length > 0) { - vm.package.contentItem = model.selection[0]; + vm.package.contentNodeId = model.selection[0].id.toString(); + vm.contentNodeDisplayModel = model.selection[0]; } editorService.close(); }, diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 796edff588..77743a1116 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -81,12 +81,10 @@ - - Date: Fri, 7 Dec 2018 10:22:33 +0000 Subject: [PATCH 039/223] Adds in validation to the POST / Create package to ensure name, author is set etc... --- src/Umbraco.Web/Editors/PackageController.cs | 16 +++++++++++----- .../Packager/PackageInstance/PackageInstance.cs | 8 ++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index a2505a1287..44efa44c21 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -24,20 +24,28 @@ namespace Umbraco.Web.Editors [HttpGet] public List GetCreatedPackages() { - //TODO: Could be too much data down the wire return CreatedPackage.GetAllCreatedPackages().Select(x => x.Data).ToList(); } [HttpGet] public PackageInstance GetCreatedPackageById(int id) { - //TODO throw an error if cant find by ID - return CreatedPackage.GetById(id).Data; + var package = CreatedPackage.GetById(id); + if (package == null) + throw new HttpResponseException(HttpStatusCode.NotFound); + + return package.Data; } [HttpPost] public PackageInstance PostCreatePackage(PackageInstance model) { + if (ModelState.IsValid == false) + { + //Throw/bubble up errors + throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + } + var newPackage = CreatedPackage.MakeNew(model.Name); var packageId = newPackage.Data.Id; var packageGuid = newPackage.Data.PackageGuid; @@ -48,8 +56,6 @@ namespace Umbraco.Web.Editors newPackage.Data.Id = packageId; newPackage.Data.PackageGuid = packageGuid; - //TODO Validation on the model?! - //Save then publish newPackage.Save(); newPackage.Publish(); diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs index 68166c9dd5..615d726dbc 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; namespace umbraco.cms.businesslogic.packager @@ -20,9 +21,12 @@ namespace umbraco.cms.businesslogic.packager public bool HasUpdate { get; set; } [DataMember(Name = "name")] + [Required] public string Name { get; set; } [DataMember(Name = "url")] + [Required] + [Url] public string Url { get; set; } [DataMember(Name = "folder")] @@ -32,6 +36,7 @@ namespace umbraco.cms.businesslogic.packager public string PackagePath { get; set; } [DataMember(Name = "version")] + [Required] public string Version { get; set; } /// @@ -41,9 +46,12 @@ namespace umbraco.cms.businesslogic.packager public Version UmbracoVersion { get; set; } [DataMember(Name = "author")] + [Required] public string Author { get; set; } [DataMember(Name = "authorUrl")] + [Required] + [Url] public string AuthorUrl { get; set; } [DataMember(Name = "license")] From 8252f4d95a34d824435c6012a24b050b2db69ac3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Dec 2018 11:31:33 +0100 Subject: [PATCH 040/223] clear create query string when using back button --- src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 6520a2ecf8..12a9ea0092 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -88,7 +88,7 @@ } function back() { - $location.path("packages/packages/overview"); + $location.path("packages/packages/overview").search('create', null);; } function createPackage() { From b35a8b406b8a6d3a2cd9aee1b393ce1dd3e29bdb Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 7 Dec 2018 10:37:33 +0000 Subject: [PATCH 041/223] Fix API Controller for Package create to support new entry & update existing entry --- src/Umbraco.Web/Editors/PackageController.cs | 33 +++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 44efa44c21..8b9e15f9d1 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -45,23 +45,34 @@ namespace Umbraco.Web.Editors //Throw/bubble up errors throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); } + + var package = new CreatedPackage + { + Data = model + }; - var newPackage = CreatedPackage.MakeNew(model.Name); - var packageId = newPackage.Data.Id; - var packageGuid = newPackage.Data.PackageGuid; + //If ID is 0 & PackageGuid is null - its brand new + if(model.Id == 0 && model.PackageGuid == null) + { + //Brand new + package = CreatedPackage.MakeNew(model.Name); - //Need to reset the package ID - as the posted model the package ID is always 0 - //MakeNew will init create the XML & update the file and give us an ID to use - newPackage.Data = model; - newPackage.Data.Id = packageId; - newPackage.Data.PackageGuid = packageGuid; + var packageId = package.Data.Id; + var packageGuid = package.Data.PackageGuid; + + //Need to reset the package ID - as the posted model the package ID is always 0 + //MakeNew will init create the XML & update the file and give us an ID to use + package.Data = model; + package.Data.Id = packageId; + package.Data.PackageGuid = packageGuid; + } //Save then publish - newPackage.Save(); - newPackage.Publish(); + package.Save(); + package.Publish(); //We should have packagepath populated now - return newPackage.Data; + return package.Data; } /// From bb5a561932ef9fc4c2f916b5a8189217844fd571 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 7 Dec 2018 11:43:36 +0000 Subject: [PATCH 042/223] Wiring up server side validation in the UI --- .../src/views/packages/edit.controller.js | 24 +++++---- .../src/views/packages/edit.html | 50 ++++++++++++++----- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 12a9ea0092..494c26e8e8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($location, $routeParams, entityResource, packageResource, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService) { + function EditController($scope, $location, $routeParams, entityResource, packageResource, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService, formHelper) { const vm = this; @@ -91,16 +91,20 @@ $location.path("packages/packages/overview").search('create', null);; } - function createPackage() { + function createPackage(editPackageForm) { - vm.createPackageButtonState = "busy"; + if (formHelper.submitForm({ formCtrl: editPackageForm, scope: $scope })) { - packageResource.createPackage(vm.package).then((updatedPackage) => { - vm.package = updatedPackage; - vm.createPackageButtonState = "success"; - }, function(error){ - vm.createPackageButtonState = "error"; - }); + vm.createPackageButtonState = "busy"; + + packageResource.createPackage(vm.package).then((updatedPackage) => { + vm.package = updatedPackage; + vm.createPackageButtonState = "success"; + }, function(err){ + formHelper.handleError(err); + vm.createPackageButtonState = "error"; + }); + } } function save() { @@ -144,7 +148,7 @@ vm.package.files.push(selected); }); } - + editorService.close(); }, close: function() { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 77743a1116..5f63d74fe7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -1,6 +1,6 @@ -
+
-
+ @@ -27,43 +27,67 @@
- + + + + Required + {{editPackageForm.url.errorMsg}} + - + + + + Required + {{editPackageForm.version.errorMsg}} + - + - + - + + + + {{editPackageForm.umbracoVersion.errorMsg}} + - + + + + Required + {{editPackageForm.author.errorMsg}} + - + + + + Required + {{editPackageForm.authorUrl.errorMsg}} + - + - + - +
@@ -281,7 +305,7 @@ Date: Fri, 7 Dec 2018 13:10:50 +0100 Subject: [PATCH 043/223] fix binding of documenttypes and templates --- .../src/views/packages/edit.controller.js | 10 ++++++++++ src/Umbraco.Web.UI.Client/src/views/packages/edit.html | 4 +--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 494c26e8e8..aa23b0209f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -54,11 +54,21 @@ // get all doc types contentTypeResource.getAll().then(documentTypes => { + // a package stores the id as a string so we + // need to convert all ids to string for comparison + documentTypes.forEach(documentType => { + documentType.id = documentType.id.toString(); + }); vm.documentTypes = documentTypes; }); // get all templates templateResource.getAll().then(templates => { + // a package stores the id as a string so we + // need to convert all ids to string for comparison + templates.forEach(template => { + template.id = template.id.toString(); + }); vm.templates = templates; }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 5f63d74fe7..4fc3ea74d1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -132,13 +132,12 @@ -
{{vm.documentTypes | json }} 
@@ -146,7 +145,6 @@ -
{{vm.templates | json }} 
\ No newline at end of file +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.html index b4ff894c4d..620f9f1731 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.html @@ -52,6 +52,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()">
-
\ No newline at end of file +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html index f14fb364ab..e48ec84b25 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html @@ -54,6 +54,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> @@ -75,4 +76,4 @@ - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html index 2ccbf11cc1..ea247c77e5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html @@ -47,6 +47,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertfield/insertfield.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertfield/insertfield.html index 56bd498fd1..16f4bfb919 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertfield/insertfield.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertfield/insertfield.html @@ -207,6 +207,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html index a50ab4242d..71fcf2f493 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html @@ -120,6 +120,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index df5bbe8ca5..4c7f2613b5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -155,6 +155,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/querybuilder/querybuilder.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/querybuilder/querybuilder.html index 4b6c6cc179..725871337d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/querybuilder/querybuilder.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/querybuilder/querybuilder.html @@ -193,6 +193,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> @@ -209,4 +210,4 @@ -
\ No newline at end of file +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html index b5b925b266..d7ba57c1af 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html @@ -86,6 +86,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> -
\ No newline at end of file +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/sectionpicker/sectionpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/sectionpicker/sectionpicker.html index 8ca1993dcc..2e88bf709c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/sectionpicker/sectionpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/sectionpicker/sectionpicker.html @@ -38,6 +38,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> -
\ No newline at end of file + diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html index d6e3996287..5b946976d7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/templatesections/templatesections.html @@ -87,6 +87,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/usergrouppicker/usergrouppicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/usergrouppicker/usergrouppicker.html index e97d80648b..e2ae1ab524 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/usergrouppicker/usergrouppicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/usergrouppicker/usergrouppicker.html @@ -84,6 +84,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/userpicker/userpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/userpicker/userpicker.html index bc6c8b5761..e39d693b47 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/userpicker/userpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/userpicker/userpicker.html @@ -74,6 +74,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI.Client/src/views/stylesheets/infiniteeditors/richtextrule/richtextrule.html b/src/Umbraco.Web.UI.Client/src/views/stylesheets/infiniteeditors/richtextrule/richtextrule.html index a36f3ef6a2..557341fe1b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/stylesheets/infiniteeditors/richtextrule/richtextrule.html +++ b/src/Umbraco.Web.UI.Client/src/views/stylesheets/infiniteeditors/richtextrule/richtextrule.html @@ -53,6 +53,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> Date: Fri, 4 Jan 2019 11:39:33 +0100 Subject: [PATCH 049/223] #3417 added create view --- src/Umbraco.Web.UI.Client/src/views/macros/create.html | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/create.html diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/create.html b/src/Umbraco.Web.UI.Client/src/views/macros/create.html new file mode 100644 index 0000000000..337ebfdaa5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/create.html @@ -0,0 +1,3 @@ +
+

Create view

+
From bb6848dd0372110be227bc9918c3ff45afc7b3ba Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Fri, 4 Jan 2019 11:44:23 +0100 Subject: [PATCH 050/223] #3417 renamed existing macrocontroller to macro rendering controller --- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 2 +- .../{MacroController.cs => MacroRenderingController.cs} | 4 ++-- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- src/Umbraco.Web/umbraco.presentation/page.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/Umbraco.Web/Editors/{MacroController.cs => MacroRenderingController.cs} (97%) diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 5bc01fa534..aab5f13479 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -169,7 +169,7 @@ namespace Umbraco.Web.Editors controller => controller.GetAllowedChildren(0)) }, { - "macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( + "macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetMacroParameters(0)) }, { diff --git a/src/Umbraco.Web/Editors/MacroController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs similarity index 97% rename from src/Umbraco.Web/Editors/MacroController.cs rename to src/Umbraco.Web/Editors/MacroRenderingController.cs index 3c576befb9..e585f28c09 100644 --- a/src/Umbraco.Web/Editors/MacroController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -27,11 +27,11 @@ namespace Umbraco.Web.Editors /// Session, we don't want it to throw null reference exceptions. /// [PluginController("UmbracoApi")] - public class MacroController : UmbracoAuthorizedJsonController, IRequiresSessionState + public class MacroRenderingController : UmbracoAuthorizedJsonController, IRequiresSessionState { private readonly IVariationContextAccessor _variationContextAccessor; - public MacroController(IVariationContextAccessor variationContextAccessor) + public MacroRenderingController(IVariationContextAccessor variationContextAccessor) { _variationContextAccessor = variationContextAccessor; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 17c2a54d81..16fbd6aa29 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -751,7 +751,7 @@ - + diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index 219e2101be..a2ccc1e094 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -102,7 +102,7 @@ namespace umbraco /// Initializes a new instance of the page for a content. /// /// The content. - /// This is for usage only. + /// This is for usage only. internal page(IContent content, IVariationContextAccessor variationContextAccessor) : this(new PagePublishedContent(content, variationContextAccessor)) { } From e1906113b969d728f6671aac15ee0e0749c545ac Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Fri, 4 Jan 2019 12:31:58 +0100 Subject: [PATCH 051/223] #3417 added macro api controller and create method --- src/Umbraco.Web/Editors/MacrosController.cs | 64 +++++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 2 files changed, 65 insertions(+) create mode 100644 src/Umbraco.Web/Editors/MacrosController.cs diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs new file mode 100644 index 0000000000..0adada0a2b --- /dev/null +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -0,0 +1,64 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Web.Http; + +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; + +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Editors +{ + /// + /// The API controller used for editing dictionary items + /// + [PluginController("UmbracoApi")] + [UmbracoTreeAuthorize(Constants.Trees.Macros)] + public class MacrosController : BackOfficeNotificationsController + { + /// + /// Creates a new macro + /// + /// + /// The name. + /// + /// + /// The . + /// + [HttpPost] + public HttpResponseMessage Create(string name) + { + if (string.IsNullOrWhiteSpace(name)) + return Request + .CreateNotificationValidationErrorResponse("Name can not be empty;"); + + var alias = name.ToSafeAlias(); + + var existingMacro = this.Services.MacroService.GetByAlias(alias); + + if (existingMacro != null) + { + return Request.CreateNotificationValidationErrorResponse("Macro with this name already exists"); + } + + try + { + var macro = new Macro { Alias = alias, Name = name }; + + this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); + + return Request.CreateResponse(HttpStatusCode.OK, macro.Id); + } + catch (Exception exception) + { + this.Logger.Error(exception, "Error creating macro"); + return Request.CreateNotificationValidationErrorResponse("Error creating dictionary item"); + } + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 16fbd6aa29..7186835ba8 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -117,6 +117,7 @@ + From c61b5f947dae03e456e1ef0ba976153768f7476b Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Fri, 4 Jan 2019 13:49:03 +0100 Subject: [PATCH 052/223] #3417 renamed server variable --- .../src/common/resources/macro.resource.js | 6 +++--- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index dde887776e..07ad58bb78 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -24,7 +24,7 @@ function macroResource($q, $http, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.get( umbRequestHelper.getApiUrl( - "macroApiBaseUrl", + "macroRenderingApiBaseUrl", "GetMacroParameters", [{ macroId: macroId }])), 'Failed to retrieve macro parameters for macro with id ' + macroId); @@ -48,7 +48,7 @@ function macroResource($q, $http, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( - "macroApiBaseUrl", + "macroRenderingApiBaseUrl", "GetMacroResultAsHtmlForEditor"), { macroAlias: macroAlias, pageId: pageId, @@ -67,7 +67,7 @@ function macroResource($q, $http, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( - "macroApiBaseUrl", + "macroRenderingApiBaseUrl", "CreatePartialViewMacroWithFile"), { virtualPath: virtualPath, filename: filename diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index aab5f13479..1550161ff0 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -169,7 +169,7 @@ namespace Umbraco.Web.Editors controller => controller.GetAllowedChildren(0)) }, { - "macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( + "macroRenderingApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetMacroParameters(0)) }, { From 03ce92212420d89f5a54f93631e8b35d796bee5c Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Fri, 4 Jan 2019 17:10:53 +0100 Subject: [PATCH 053/223] #3417 register new api url in server variables --- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 1550161ff0..52cfc1bdec 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -172,6 +172,10 @@ namespace Umbraco.Web.Editors "macroRenderingApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetMacroParameters(0)) }, + { + "macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( + controller => controller.Create(null)) + }, { "authenticationApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.PostLogin(null)) From d7af9d9fca9ec0760dfa88fb7a710fe5359a4e36 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Fri, 4 Jan 2019 17:36:42 +0100 Subject: [PATCH 054/223] #3417 added method to macro resource to create a macro --- .../src/common/resources/macro.resource.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index 07ad58bb78..d0c6af2497 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -76,6 +76,19 @@ function macroResource($q, $http, umbRequestHelper) { 'Failed to create macro "' + filename + '"' ); + }, + + createMacro: function(name) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "macroApiBaseUrl", + "Create"), { + name : name, + } + ), + 'Failed to create macro "' + name + '"' + ); } }; } From 2ca7bb0cf3751077a35af9a61995df171e7274e9 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Mon, 7 Jan 2019 08:28:50 +0100 Subject: [PATCH 055/223] #3417 implemented create dialog for macros --- .../src/common/resources/macro.resource.js | 4 +- .../src/views/macros/create.html | 20 ++++++++- .../views/macros/macros.create.controller.js | 44 +++++++++++++++++++ src/Umbraco.Web/Editors/MacrosController.cs | 2 +- 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index d0c6af2497..9f22465757 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -83,9 +83,7 @@ function macroResource($q, $http, umbRequestHelper) { $http.post( umbRequestHelper.getApiUrl( "macroApiBaseUrl", - "Create"), { - name : name, - } + "Create?name=" + name) ), 'Failed to create macro "' + name + '"' ); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/create.html b/src/Umbraco.Web.UI.Client/src/views/macros/create.html index 337ebfdaa5..a72cd373b2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/create.html @@ -1,3 +1,19 @@ -
-

Create view

+
+ +
+
Create an item under {{currentNode.name}}
+
+ +
+
+ + + + + + +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js new file mode 100644 index 0000000000..1745b7b7f6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js @@ -0,0 +1,44 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.CreateController + * @function + * + * @description + * The controller for creating macro items + */ +function MacrosCreateController($scope, $location, macroResource, navigationService, notificationsService, formHelper, appState) { + var vm = this; + + vm.itemKey = ""; + + function createItem() { + + var node = $scope.currentNode; + + macroResource.createMacro(vm.itemKey).then(function (data) { + navigationService.hideMenu(); + + // set new item as active in tree + var currPath = node.path ? node.path : "-1"; + navigationService.syncTree({ tree: "macros", path: currPath + "," + data, forceReload: true, activate: true }); + + // reset form state + formHelper.resetForm({ scope: $scope }); + + // navigate to edit view + var currentSection = appState.getSectionState("currentSection"); + $location.path("/" + currentSection + "/macros/edit/" + data); + + + }, function (err) { + if (err.data && err.data.message) { + notificationsService.error(err.data.message); + navigationService.hideMenu(); + } + }); + } + + vm.createItem = createItem; +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.CreateController", MacrosCreateController); diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 0adada0a2b..f1d949231e 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -48,7 +48,7 @@ namespace Umbraco.Web.Editors try { - var macro = new Macro { Alias = alias, Name = name }; + var macro = new Macro { Alias = alias, Name = name, MacroSource = string.Empty}; this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); From edd2adc8a00db041b2ee7f073969ea0b5c58bdb9 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Mon, 7 Jan 2019 08:31:06 +0100 Subject: [PATCH 056/223] #3417 changed path of macro tree item to use angular view instead of webform --- src/Umbraco.Web/Trees/MacrosTreeController.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Trees/MacrosTreeController.cs b/src/Umbraco.Web/Trees/MacrosTreeController.cs index 0649378aaa..f16cfe09d4 100644 --- a/src/Umbraco.Web/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/MacrosTreeController.cs @@ -42,10 +42,7 @@ namespace Umbraco.Web.Trees queryStrings, macro.Name, "icon-settings-alt", - false, - //TODO: Rebuild the macro editor in angular, then we dont need to have this at all (which is just a path to the legacy editor) - "/" + queryStrings.GetValue("application") + "/framed/" + - Uri.EscapeDataString("/umbraco/developer/macros/editMacro.aspx?macroID=" + macro.Id))); + false)); } } From b9d779e921a116dd86a04df25ff7ce3252a3269b Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Tue, 8 Jan 2019 08:34:46 +0100 Subject: [PATCH 057/223] #3417 prototyped the UI for settings of the macro --- .../src/views/macros/edit.html | 31 +++++++ .../views/macros/macros.edit.controller.js | 87 +++++++++++++++++++ .../src/views/macros/views/parameters.html | 3 + .../src/views/macros/views/settings.html | 33 +++++++ 4 files changed, 154 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/edit.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/edit.html b/src/Umbraco.Web.UI.Client/src/views/macros/edit.html new file mode 100644 index 0000000000..911dcf0c9e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/edit.html @@ -0,0 +1,31 @@ +
+ + +
+ + + + + + + + + + + + + + + + +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js new file mode 100644 index 0000000000..ef65c77e1d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js @@ -0,0 +1,87 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.EditController + * @function + * + * @description + * The controller for editing macros. + */ +function MacrosEditController($scope, $routeParams, macroResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService) { + + var vm = this; + + vm.page = {}; + vm.page.loading = false; + vm.page.saveButtonState = "init"; + vm.page.menu = {} + + vm.save = saveMacro; + vm.toggle = toggleValue; + + init(); + + function init() { + vm.page.loading = true; + + + vm.page.navigation = [ + { + "name": "Settings", + "alias": "settings", + "icon": "icon-settings", + "view": "views/macros/views/settings.html", + "active": true + }, + { + "name": "Parameters", + "alias": "parameters", + "icon": "icon-list", + "view": "views/macros/views/parameters.html" + } + ]; + + vm.macro = { + "name": "Test macro", + "alias": "testMacro", + "id": 1, + "key": "unique key goes here", + "useInEditor": true, + "renderInEditor": false, + "cachePeriod": 2400, + "cacheByPage": true, + "cacheByUser": false, + "view" : "Second" + } + + vm.views = ['First', 'Second', 'Third']; + + vm.page.loading = false; + } + + function toggleValue(key) { + vm.macro[key] = !vm.macro[key]; + } + + function saveMacro() { + vm.page.saveButtonState = "busy"; + + if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) { + console.log(vm.macro); + //relationTypeResource.save(vm.relationType).then(function (data) { + // formHelper.resetForm({ scope: $scope, notifications: data.notifications }); + // bindRelationType(data); + // vm.page.saveButtonState = "success"; + //}, function (error) { + // contentEditingHelper.handleSaveError({ + // redirectOnFailure: false, + // err: error + // }); + + // notificationsService.error(error.data.message); + // vm.page.saveButtonState = "error"; + //}); + } + } +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.EditController", MacrosEditController); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html new file mode 100644 index 0000000000..6a10d4f80b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html @@ -0,0 +1,3 @@ + + + diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html new file mode 100644 index 0000000000..51e83a9134 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 640de1c1a46f24cbbe93eb9f9a5a81b70f04a528 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 9 Jan 2019 18:59:59 +1100 Subject: [PATCH 058/223] very small cleanup before some package code changes --- .../Events/ImportPackageEventArgs.cs | 26 +---- src/Umbraco.Web.UI.Client/package-lock.json | 100 +++++++++--------- src/Umbraco.Web/_Legacy/Packager/Installer.cs | 24 ++--- .../PackageInstance/InstalledPackage.cs | 39 ++++--- 4 files changed, 93 insertions(+), 96 deletions(-) diff --git a/src/Umbraco.Core/Events/ImportPackageEventArgs.cs b/src/Umbraco.Core/Events/ImportPackageEventArgs.cs index 2e56757a25..ba356ff952 100644 --- a/src/Umbraco.Core/Events/ImportPackageEventArgs.cs +++ b/src/Umbraco.Core/Events/ImportPackageEventArgs.cs @@ -7,20 +7,10 @@ namespace Umbraco.Core.Events { public class ImportPackageEventArgs : CancellableEnumerableObjectEventArgs, IEquatable> { - private readonly MetaData _packageMetaData; - - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use the overload specifying packageMetaData instead")] - public ImportPackageEventArgs(TEntity eventObject, bool canCancel) - : base(new[] { eventObject }, canCancel) - { - } - public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData, bool canCancel) : base(new[] { eventObject }, canCancel) { - if (packageMetaData == null) throw new ArgumentNullException("packageMetaData"); - _packageMetaData = packageMetaData; + PackageMetaData = packageMetaData ?? throw new ArgumentNullException(nameof(packageMetaData)); } public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData) @@ -29,22 +19,16 @@ namespace Umbraco.Core.Events } - public MetaData PackageMetaData - { - get { return _packageMetaData; } - } + public MetaData PackageMetaData { get; } - public IEnumerable InstallationSummary - { - get { return EventObject; } - } + public IEnumerable InstallationSummary => EventObject; public bool Equals(ImportPackageEventArgs other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; //TODO: MetaData for package metadata has no equality operators :/ - return base.Equals(other) && _packageMetaData.Equals(other._packageMetaData); + return base.Equals(other) && PackageMetaData.Equals(other.PackageMetaData); } public override bool Equals(object obj) @@ -59,7 +43,7 @@ namespace Umbraco.Core.Events { unchecked { - return (base.GetHashCode() * 397) ^ _packageMetaData.GetHashCode(); + return (base.GetHashCode() * 397) ^ PackageMetaData.GetHashCode(); } } diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 7c3fe8b4f9..750be3fa80 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -917,7 +917,7 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { @@ -935,7 +935,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -1150,7 +1150,7 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-sort": { @@ -1196,7 +1196,7 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, "asap": { @@ -1249,7 +1249,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, "asynckit": { @@ -2327,7 +2327,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -2407,7 +2407,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "continuable-cache": { @@ -2450,7 +2450,7 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", "dev": true }, "core-util-is": { @@ -3373,7 +3373,7 @@ "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -3901,7 +3901,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -3937,7 +3937,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -4101,7 +4101,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -4196,7 +4196,7 @@ "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -4206,13 +4206,13 @@ "eslint-utils": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", "dev": true }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, "espree": { @@ -4235,7 +4235,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -4244,7 +4244,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -4304,7 +4304,7 @@ "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", "dev": true }, "exec-buffer": { @@ -4519,7 +4519,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { "is-number": "^2.1.0", @@ -5833,7 +5833,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -6397,7 +6397,7 @@ "gulp-eslint": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz", - "integrity": "sha1-KiaECV93Syz3kxAmIHjFbMehK1I=", + "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", "dev": true, "requires": { "eslint": "^5.0.1", @@ -7255,7 +7255,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { "isarray": "2.0.1" @@ -7406,7 +7406,7 @@ "http-proxy": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { "eventemitter3": "^3.0.0", @@ -7700,7 +7700,7 @@ "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -7995,7 +7995,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -8004,7 +8004,7 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retry-allowed": { @@ -8052,7 +8052,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -8209,7 +8209,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -8336,7 +8336,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -8986,7 +8986,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -9167,7 +9167,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { @@ -12683,7 +12683,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "posix-character-classes": { @@ -13106,7 +13106,7 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, @@ -13173,7 +13173,7 @@ "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { @@ -13369,7 +13369,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -13867,7 +13867,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "sax": { @@ -14054,7 +14054,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, "shebang-command": { @@ -14338,7 +14338,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -14618,7 +14618,7 @@ "stream-consume": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", "dev": true }, "stream-shift": { @@ -14630,7 +14630,7 @@ "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", "dev": true, "requires": { "date-format": "^1.2.0", @@ -14657,7 +14657,7 @@ "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -14672,7 +14672,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14689,7 +14689,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -15231,7 +15231,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -15395,7 +15395,7 @@ "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, "requires": { "media-typer": "0.3.0", @@ -15437,7 +15437,7 @@ "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, "unc-path-regex": { @@ -15599,13 +15599,13 @@ "upath": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0=", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -15660,7 +15660,7 @@ "dependencies": { "lru-cache": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", "dev": true } @@ -16040,7 +16040,7 @@ "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { "async-limiter": "~1.0.0", diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 020e34d4ce..44278a41e0 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -37,13 +37,11 @@ namespace umbraco.cms.businesslogic.packager { private const string PackageServer = "packages.umbraco.org"; - private readonly List _unsecureFiles = new List(); private readonly Dictionary _conflictingMacroAliases = new Dictionary(); private readonly Dictionary _conflictingTemplateAliases = new Dictionary(); private readonly Dictionary _conflictingStyleSheetNames = new Dictionary(); - private readonly List _binaryFileErrors = new List(); - private int _currentUserId = -1; + private readonly int _currentUserId = -1; private static WebClient _webClient; @@ -58,13 +56,13 @@ namespace umbraco.cms.businesslogic.packager public string Control { get; private set; } public bool ContainsMacroConflict { get; private set; } - public IDictionary ConflictingMacroAliases { get { return _conflictingMacroAliases; } } + public IDictionary ConflictingMacroAliases => _conflictingMacroAliases; public bool ContainsUnsecureFiles { get; private set; } - public List UnsecureFiles { get { return _unsecureFiles; } } + public List UnsecureFiles { get; } = new List(); public bool ContainsTemplateConflicts { get; private set; } - public IDictionary ConflictingTemplateAliases { get { return _conflictingTemplateAliases; } } + public IDictionary ConflictingTemplateAliases => _conflictingTemplateAliases; /// /// Indicates that the package contains assembly reference errors @@ -74,10 +72,10 @@ namespace umbraco.cms.businesslogic.packager /// /// List each assembly reference error /// - public List BinaryFileErrors { get { return _binaryFileErrors; } } + public List BinaryFileErrors { get; } = new List(); public bool ContainsStyleSheeConflicts { get; private set; } - public IDictionary ConflictingStyleSheetNames { get { return _conflictingStyleSheetNames; } } + public IDictionary ConflictingStyleSheetNames => _conflictingStyleSheetNames; public int RequirementsMajor { get; private set; } public int RequirementsMinor { get; private set; } @@ -603,7 +601,7 @@ namespace umbraco.cms.businesslogic.packager if (badFile) { ContainsUnsecureFiles = true; - _unsecureFiles.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + UnsecureFiles.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); } } @@ -816,8 +814,8 @@ namespace umbraco.cms.businesslogic.packager private static void OnPackageBusinessLogicInstalled(InstalledPackage e) { - EventHandler handler = PackageBusinessLogicInstalled; - if (handler != null) handler(null, e); + var handler = PackageBusinessLogicInstalled; + handler?.Invoke(null, e); } private void OnPackageInstalled(InstalledPackage insPack) @@ -832,7 +830,9 @@ namespace umbraco.cms.businesslogic.packager var installationSummary = insPack.GetInstallationSummary(contentTypeService, dataTypeService, fileService, localizationService, macroService); installationSummary.PackageInstalled = true; - var args = new ImportPackageEventArgs(installationSummary, false); + var meta = insPack.GetMetaData(); + + var args = new ImportPackageEventArgs(installationSummary, meta, false); PackagingService.OnImportedPackage(args); } } diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs index 9e04bff636..4136029485 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs @@ -9,25 +9,29 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services; -namespace umbraco.cms.businesslogic.packager { +namespace umbraco.cms.businesslogic.packager +{ public class InstalledPackage { private int _saveHitCount = 0; - public static InstalledPackage GetById(int id) { + public static InstalledPackage GetById(int id) + { InstalledPackage pack = new InstalledPackage(); pack.Data = data.Package(id, IOHelper.MapPath(Settings.InstalledPackagesSettings)); return pack; } - public static InstalledPackage GetByGuid(string packageGuid) { + public static InstalledPackage GetByGuid(string packageGuid) + { InstalledPackage pack = new InstalledPackage(); pack.Data = data.Package(packageGuid, IOHelper.MapPath(Settings.InstalledPackagesSettings)); return pack; } - public static InstalledPackage MakeNew(string name) { + public static InstalledPackage MakeNew(string name) + { InstalledPackage pack = new InstalledPackage(); pack.Data = data.MakeNew(name, IOHelper.MapPath(Settings.InstalledPackagesSettings)); pack.OnNew(EventArgs.Empty); @@ -45,7 +49,8 @@ namespace umbraco.cms.businesslogic.packager { this.FireAfterSave(EventArgs.Empty); } - public static List GetAllInstalledPackages() { + public static List GetAllInstalledPackages() + { List val = new List(); @@ -60,7 +65,8 @@ namespace umbraco.cms.businesslogic.packager { } private PackageInstance m_data; - public PackageInstance Data { + public PackageInstance Data + { get { return m_data; } set { m_data = value; } } @@ -71,13 +77,15 @@ namespace umbraco.cms.businesslogic.packager { Delete(); } - public void Delete() { + public void Delete() + { this.FireBeforeDelete(EventArgs.Empty); data.Delete(this.Data.Id, IOHelper.MapPath(Settings.InstalledPackagesSettings)); this.FireAfterDelete(EventArgs.Empty); } - public static bool isPackageInstalled(string packageGuid) { + public static bool isPackageInstalled(string packageGuid) + { try { if (data.GetFromGuid(packageGuid, IOHelper.MapPath(Settings.InstalledPackagesSettings), true) == null) @@ -101,31 +109,36 @@ namespace umbraco.cms.businesslogic.packager { /// Occurs when a macro is saved. /// public static event SaveEventHandler BeforeSave; - protected virtual void FireBeforeSave(EventArgs e) { + protected virtual void FireBeforeSave(EventArgs e) + { if (BeforeSave != null) BeforeSave(this, e); } public static event SaveEventHandler AfterSave; - protected virtual void FireAfterSave(EventArgs e) { + protected virtual void FireAfterSave(EventArgs e) + { if (AfterSave != null) AfterSave(this, e); } public static event NewEventHandler New; - protected virtual void OnNew(EventArgs e) { + protected virtual void OnNew(EventArgs e) + { if (New != null) New(this, e); } public static event DeleteEventHandler BeforeDelete; - protected virtual void FireBeforeDelete(EventArgs e) { + protected virtual void FireBeforeDelete(EventArgs e) + { if (BeforeDelete != null) BeforeDelete(this, e); } public static event DeleteEventHandler AfterDelete; - protected virtual void FireAfterDelete(EventArgs e) { + protected virtual void FireAfterDelete(EventArgs e) + { if (AfterDelete != null) AfterDelete(this, e); } From a955ef2b36319fa23baf4f97e13fc67c9a9c0660 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 9 Jan 2019 19:05:01 +1100 Subject: [PATCH 059/223] Align namespaces with _Legacy folder --- .../Editors/PackageInstallController.cs | 15 ++++++------ .../Controllers/InstallPackageController.cs | 8 +++---- .../InstallSteps/StarterKitCleanupStep.cs | 2 +- .../InstallSteps/StarterKitDownloadStep.cs | 3 ++- .../InstallSteps/StarterKitInstallStep.cs | 2 +- .../Trees/PackagesTreeController.cs | 2 +- src/Umbraco.Web/_Legacy/Packager/Installer.cs | 14 ++++++----- .../PackageInstance/CreatedPackage.cs | 3 +-- .../PackageInstance/IPackageInstance.cs | 3 +-- .../PackageInstance/InstalledPackage.cs | 5 ++-- .../PackageInstance/PackageActions.cs | 4 +--- .../PackageInstance/PackageInstance.cs | 5 +--- .../PackageInstance/PackagerUtility.cs | 2 +- .../_Legacy/Packager/RequirementsType.cs | 2 +- src/Umbraco.Web/_Legacy/Packager/Settings.cs | 10 +------- src/Umbraco.Web/_Legacy/Packager/data.cs | 24 +++++++++---------- .../umbraco/create/CreatedPackageTasks.cs | 2 +- .../developer/Packages/editPackage.aspx.cs | 15 ++++++------ 18 files changed, 55 insertions(+), 66 deletions(-) diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 94465feab8..aee74551ea 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -8,7 +8,6 @@ using System.Net.Http; using System.Threading.Tasks; using System.Web.Http; using System.Xml; -using umbraco.cms.businesslogic.packager; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Events; @@ -26,6 +25,8 @@ using Umbraco.Web.UI; using Umbraco.Web.UI.JavaScript; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; +using Umbraco.Web._Legacy.Packager; +using Umbraco.Web._Legacy.Packager.PackageInstance; using File = System.IO.File; using Notification = Umbraco.Web.Models.ContentEditing.Notification; using Version = System.Version; @@ -194,7 +195,7 @@ namespace Umbraco.Web.Editors { try { - global::umbraco.cms.businesslogic.packager.PackageAction + global::Umbraco.Web._Legacy.Packager.PackageInstance.PackageAction .UndoPackageAction(pack.Data.Name, n.Attributes["alias"].Value, n); } catch (Exception ex) @@ -310,7 +311,7 @@ namespace Umbraco.Web.Editors private void PopulateFromPackageData(LocalPackageInstallModel model) { - var ins = new global::umbraco.cms.businesslogic.packager.Installer(Security.CurrentUser.Id); + var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); //this will load in all the metadata too var tempDir = ins.Import(model.ZipFilePath, false); @@ -500,7 +501,7 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel Import(PackageInstallModel model) { - var ins = new global::umbraco.cms.businesslogic.packager.Installer(Security.CurrentUser.Id); + var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); var tempPath = ins.Import(model.ZipFilePath); //now we need to check for version comparison @@ -528,7 +529,7 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel InstallFiles(PackageInstallModel model) { - var ins = new global::umbraco.cms.businesslogic.packager.Installer(Security.CurrentUser.Id); + var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); ins.InstallFiles(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); @@ -562,7 +563,7 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel InstallData(PackageInstallModel model) { - var ins = new global::umbraco.cms.businesslogic.packager.Installer(Security.CurrentUser.Id); + var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); ins.InstallBusinessLogic(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); return model; @@ -576,7 +577,7 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallResult CleanUp(PackageInstallModel model) { - var ins = new global::umbraco.cms.businesslogic.packager.Installer(Security.CurrentUser.Id); + var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); var tempDir = IOHelper.MapPath(model.TemporaryDirectoryPath); ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); ins.InstallCleanUp(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs index eb7d02053b..1fd2ac27bb 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.Install.Controllers UmbracoVersion.Current, UmbracoContext.Current.Security.CurrentUser.Id); - var installer = new global::umbraco.cms.businesslogic.packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); + var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); var tempFile = installer.Import(packageFile); installer.LoadConfig(tempFile); @@ -79,7 +79,7 @@ namespace Umbraco.Web.Install.Controllers public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) { model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var installer = new global::umbraco.cms.businesslogic.packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); + var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); installer.LoadConfig(model.PackageFile); installer.InstallFiles(model.ManifestId, model.PackageFile); return Json(new @@ -135,7 +135,7 @@ namespace Umbraco.Web.Install.Controllers public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) { model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var installer = new global::umbraco.cms.businesslogic.packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); + var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); installer.LoadConfig(model.PackageFile); installer.InstallBusinessLogic(model.ManifestId, model.PackageFile); return Json(new @@ -156,7 +156,7 @@ namespace Umbraco.Web.Install.Controllers public HttpResponseMessage CleanupInstallation(InstallPackageModel model) { model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var installer = new global::umbraco.cms.businesslogic.packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); + var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); installer.LoadConfig(model.PackageFile); installer.InstallCleanUp(model.ManifestId, model.PackageFile); diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs index 5738f2a67c..9345a0fc96 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs @@ -1,8 +1,8 @@ using System; using System.Linq; using System.Web; -using umbraco.cms.businesslogic.packager; using Umbraco.Web.Install.Models; +using Umbraco.Web._Legacy.Packager; namespace Umbraco.Web.Install.InstallSteps { diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index b8ae600dba..8f9f9242d7 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Web; -using umbraco.cms.businesslogic.packager; using Umbraco.Core.Services; using Umbraco.Core.Configuration; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; using Umbraco.Web.Security; +using Umbraco.Web._Legacy.Packager; +using Umbraco.Web._Legacy.Packager.PackageInstance; namespace Umbraco.Web.Install.InstallSteps { diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 844a27a576..8bec4ca199 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -1,9 +1,9 @@ using System; using System.Linq; using System.Web; -using umbraco.cms.businesslogic.packager; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; +using Umbraco.Web._Legacy.Packager; namespace Umbraco.Web.Install.InstallSteps { diff --git a/src/Umbraco.Web/Trees/PackagesTreeController.cs b/src/Umbraco.Web/Trees/PackagesTreeController.cs index 80e48c9242..c56ed716a1 100644 --- a/src/Umbraco.Web/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/PackagesTreeController.cs @@ -4,9 +4,9 @@ using System.Net.Http.Formatting; using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi.Filters; -using umbraco.cms.businesslogic.packager; using Umbraco.Core.Services; using Umbraco.Web.Actions; +using Umbraco.Web._Legacy.Packager.PackageInstance; using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 44278a41e0..15ea222bda 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -1,24 +1,26 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; -using System.Xml; using System.Linq; +using System.Net; +using System.Xml; using ICSharpCode.SharpZipLib.Zip; using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; -using System.Diagnostics; using Umbraco.Core.Models; -using Umbraco.Core.Composing; -using System.Net; -using Umbraco.Core.Events; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services.Implement; using Umbraco.Core.Xml; +using Umbraco.Web._Legacy.Packager.PackageInstance; using File = System.IO.File; +using PackageAction = Umbraco.Web._Legacy.Packager.PackageInstance.PackageAction; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager { /// /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs index 5d811ed3d8..3bfcdd3f86 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Xml; -using Lucene.Net.Documents; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.IO; @@ -11,7 +10,7 @@ using Umbraco.Core.Services; using File = System.IO.File; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager.PackageInstance { public class CreatedPackage { diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs index 28c7c05b6b..b920c85a9f 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs @@ -1,5 +1,4 @@ -using System; -namespace umbraco.cms.businesslogic.packager{ +namespace Umbraco.Web._Legacy.Packager.PackageInstance{ public interface IPackageInstance { string Actions { get; set; } string Author { get; set; } diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs index 4136029485..5842a456e5 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager.PackageInstance { public class InstalledPackage { diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs index d1df47cd44..bfd1030d85 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs @@ -1,12 +1,10 @@ using System; using System.Xml; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core._Legacy.PackageActions; - -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager.PackageInstance { /// diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs index 8f7cb56320..fe32633ccd 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs @@ -1,10 +1,7 @@ using System; - -using System.Xml; -using System.Xml.XPath; using System.Collections.Generic; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager.PackageInstance { public class PackageInstance { diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs index 53ed58810c..d972977bad 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Services; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager.PackageInstance { /// /// A utillity class for working with packager data. diff --git a/src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs b/src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs index ea63ff6979..ca91626128 100644 --- a/src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs +++ b/src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs @@ -1,4 +1,4 @@ -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager { public enum RequirementsType { diff --git a/src/Umbraco.Web/_Legacy/Packager/Settings.cs b/src/Umbraco.Web/_Legacy/Packager/Settings.cs index 85cfebcfee..57ab4b9ea4 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Settings.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Settings.cs @@ -1,16 +1,8 @@ using System; -using System.Data; -using System.Configuration; -using System.Web; -using System.Web.Security; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Web.UI.WebControls.WebParts; -using System.Web.UI.HtmlControls; using System.IO; using Umbraco.Core.IO; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager { public class Settings { diff --git a/src/Umbraco.Web/_Legacy/Packager/data.cs b/src/Umbraco.Web/_Legacy/Packager/data.cs index 88cc7a4b54..962b7d5ed4 100644 --- a/src/Umbraco.Web/_Legacy/Packager/data.cs +++ b/src/Umbraco.Web/_Legacy/Packager/data.cs @@ -1,15 +1,15 @@ using System; -using System.Xml; using System.Collections.Generic; using System.IO; +using System.Xml; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Xml; -namespace umbraco.cms.businesslogic.packager +namespace Umbraco.Web._Legacy.Packager { /// /// This is the xml data for installed packages. This is not the same xml as a pckage format! @@ -85,7 +85,7 @@ namespace umbraco.cms.businesslogic.packager return Source.SelectSingleNode("/packages/package [@packageGuid = '" + guid + "']"); } - public static PackageInstance MakeNew(string Name, string dataSource) + public static PackageInstance.PackageInstance MakeNew(string Name, string dataSource) { Reload(dataSource); @@ -151,26 +151,26 @@ namespace umbraco.cms.businesslogic.packager return retVal; } - public static PackageInstance Package(int id, string datasource) + public static PackageInstance.PackageInstance Package(int id, string datasource) { return ConvertXmlToPackage(GetFromId(id, datasource, true)); } - public static PackageInstance Package(string guid, string datasource) + public static PackageInstance.PackageInstance Package(string guid, string datasource) { XmlNode node = GetFromGuid(guid, datasource, true); if (node != null) return ConvertXmlToPackage(node); else - return new PackageInstance(); + return new PackageInstance.PackageInstance(); } - public static List GetAllPackages(string dataSource) + public static List GetAllPackages(string dataSource) { Reload(dataSource); XmlNodeList nList = data.Source.SelectNodes("packages/package"); - List retVal = new List(); + List retVal = new List(); for (int i = 0; i < nList.Count; i++) { @@ -187,9 +187,9 @@ namespace umbraco.cms.businesslogic.packager return retVal; } - private static PackageInstance ConvertXmlToPackage(XmlNode n) + private static PackageInstance.PackageInstance ConvertXmlToPackage(XmlNode n) { - PackageInstance retVal = new PackageInstance(); + PackageInstance.PackageInstance retVal = new PackageInstance.PackageInstance(); if (n != null) { @@ -263,7 +263,7 @@ namespace umbraco.cms.businesslogic.packager } - public static void Save(PackageInstance package, string dataSource) + public static void Save(PackageInstance.PackageInstance package, string dataSource) { Reload(dataSource); var xmlDef = GetFromId(package.Id, dataSource, false); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs index 64f2c94b0a..47980f2808 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs @@ -3,8 +3,8 @@ using Umbraco.Web.UI; using Umbraco.Core; using Umbraco.Web; using Umbraco.Web.Composing; +using Umbraco.Web._Legacy.Packager.PackageInstance; using Umbraco.Web._Legacy.UI; -using umbraco.cms.businesslogic.packager; namespace Umbraco.Web { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs index 22a9f4292f..645aa088f2 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs @@ -12,6 +12,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Web.UI; using Umbraco.Web.UI.Pages; +using Umbraco.Web._Legacy.Packager.PackageInstance; namespace umbraco.presentation.developer.packages { @@ -31,14 +32,14 @@ namespace umbraco.presentation.developer.packages public Umbraco.Web._Legacy.Controls.TabPage packageActions; protected ContentPicker cp; - private cms.businesslogic.packager.PackageInstance pack; - private cms.businesslogic.packager.CreatedPackage createdPackage; + private PackageInstance pack; + private CreatedPackage createdPackage; protected void Page_Load(object sender, EventArgs e) { if (Request.QueryString["id"] != null) { - createdPackage = cms.businesslogic.packager.CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); + createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); pack = createdPackage.Data; /* CONTENT */ @@ -359,8 +360,8 @@ namespace umbraco.presentation.developer.packages if (newPath.Trim() != "") { - cms.businesslogic.packager.CreatedPackage createdPackage = cms.businesslogic.packager.CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - cms.businesslogic.packager.PackageInstance pack = createdPackage.Data; + CreatedPackage createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); + PackageInstance pack = createdPackage.Data; pack.Files.Add(newPath); @@ -386,8 +387,8 @@ namespace umbraco.presentation.developer.packages tmpFilePathString += tmpFFFF + "�"; } - cms.businesslogic.packager.CreatedPackage createdPackage = cms.businesslogic.packager.CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - cms.businesslogic.packager.PackageInstance pack = createdPackage.Data; + CreatedPackage createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); + PackageInstance pack = createdPackage.Data; pack.Files = new List(tmpFilePathString.Trim('�').Split('�')); pack.Files.TrimExcess(); From a809e35e5d07117c9a2d3d54050685c3253335da Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 9 Jan 2019 11:29:42 +0100 Subject: [PATCH 060/223] Fixes - temp8-40120 tags-validation-bug --- .../directives/components/tags/umbtagseditor.directive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index 8bad5ae8fd..fea7528d5b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -189,7 +189,7 @@ */ function validateMandatory() { return { - isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0), + isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0) || (vm.value != null && vm.value.length > 0), errorMsg: "Value cannot be empty", errorKey: "required" }; From fe689e68551d20e8c733752132f5cc216e5db43f Mon Sep 17 00:00:00 2001 From: elitsa Date: Wed, 9 Jan 2019 12:08:46 +0100 Subject: [PATCH 061/223] Added timeout to for rebinding editor shortcuts, and a shortcut for a media picker. --- .../src/common/services/editor.service.js | 10 ++++++---- .../infiniteeditors/mediapicker/mediapicker.html | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index 0d6432b01f..c495c4e7a1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -162,7 +162,7 @@ When building a custom infinite editor view you can use the same components as a (function () { "use strict"; - function editorService(eventsService, keyboardService) { + function editorService(eventsService, keyboardService, $timeout) { let editorsKeyboardShorcuts = []; var editors = []; @@ -246,9 +246,11 @@ When building a custom infinite editor view you can use the same components as a // emit event to let components know an editor has been removed eventsService.emit("appState.editors.close", args); - // rebind keyboard shortcuts for the new editor in focus - rebindKeyboardShortcuts(); - + $timeout(function() { + // rebind keyboard shortcuts for the new editor in focus + rebindKeyboardShortcuts(); + }, 0); + } /** diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html index 3bb694cac6..cac412df8b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html @@ -171,6 +171,7 @@ From 5f972384b1968be616ff6873422ee5bbf3c43fee Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 10 Jan 2019 12:44:57 +1100 Subject: [PATCH 062/223] WIP - new IEntityXmlSerializer, IPackageCreation, PackageActionRunner, large refactor of entity serialization, no more IPackagingService.Export methods, ports legacy package creation code to new IPackageCreation, more more ExportEventArgs (makes no sense) --- .../Composing/Composers/ServicesComposer.cs | 7 + src/Umbraco.Core/Composing/Current.cs | 4 + src/Umbraco.Core/ContentExtensions.cs | 65 +- src/Umbraco.Core/Events/ExportEventArgs.cs | 86 --- .../Models/Packaging/ActionRunAt.cs | 9 + .../Models/Packaging/InstallationSummary.cs | 19 - .../InstallationSummaryExtentions.cs | 23 + .../Models/Packaging/PackageAction.cs | 10 +- .../Models/Packaging/PackageDefinition.cs | 108 ++++ .../Packaging}/UninstallationSummary.cs | 22 +- .../UninstallationSummaryExtentions.cs | 22 + .../Packaging/IPackageCreation.cs | 22 + .../Packaging/IPackageInstallation.cs | 3 + .../Packaging/PackageActionRunner.cs} | 32 +- src/Umbraco.Core/Packaging/PackageCreation.cs | 564 ++++++++++++++++++ .../Services/IEntityXmlSerializer.cs | 88 +++ .../Services/IPackagingService.cs | 118 +--- .../Services/Implement/EntityService.cs | 3 + .../{ => Implement}/EntityXmlSerializer.cs | 226 +++++-- .../Services/Implement/PackagingService.cs | 470 ++------------- src/Umbraco.Core/Umbraco.Core.csproj | 14 +- .../PackageActions/PackageActionCollection.cs | 2 +- .../PublishedContentCacheTests.cs | 3 +- .../PublishedMediaCacheTests.cs | 9 +- src/Umbraco.Tests/Models/ContentXmlTest.cs | 4 +- src/Umbraco.Tests/Models/MediaXmlTest.cs | 3 +- .../PublishedContent/NuCacheTests.cs | 3 +- .../PublishedContent/PublishedMediaTests.cs | 23 +- .../Scoping/ScopedNuCacheTests.cs | 3 +- .../ContentTypeServiceVariantsTests.cs | 3 +- .../Services/EntityXmlSerializerTests.cs | 101 ++++ .../Services/Importing/PackageImportTests.cs | 4 +- .../Services/PackagingServiceTests.cs | 88 +-- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 6 +- .../TestHelpers/TestWithDatabaseBase.cs | 1 + src/Umbraco.Tests/UI/LegacyDialogTests.cs | 1 - src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + .../Web/Mvc/UmbracoViewPageTests.cs | 6 +- src/Umbraco.Web/Composing/Current.cs | 3 + .../Editors/ContentTypeController.cs | 20 +- .../Editors/ContentTypeControllerBase.cs | 14 +- .../Editors/MediaTypeController.cs | 11 + .../Editors/MemberTypeController.cs | 12 + src/Umbraco.Web/Editors/PackageController.cs | 66 +- .../Editors/PackageInstallController.cs | 22 +- .../UmbracoAuthorizedJsonController.cs | 31 +- .../ContentEditing/UmbracoEntityTypes.cs | 2 + .../PublishedCache/NuCache/MemberCache.cs | 13 +- .../NuCache/PublishedSnapshotService.cs | 7 +- .../XmlPublishedCache/PublishedMediaCache.cs | 21 +- .../PublishedSnapshotService.cs | 38 +- .../XmlPublishedCache/XmlStore.cs | 44 +- src/Umbraco.Web/Services/SectionService.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 4 - src/Umbraco.Web/_Legacy/Packager/Installer.cs | 8 +- .../PackageInstance/CreatedPackage.cs | 49 +- .../PackageInstance/IPackageInstance.cs | 27 - .../PackageInstance/InstalledPackage.cs | 8 +- .../PackageInstance/PackageInstance.cs | 132 ---- .../PackageInstance/PackagerUtility.cs | 51 +- src/Umbraco.Web/_Legacy/Packager/Settings.cs | 64 +- src/Umbraco.Web/_Legacy/Packager/data.cs | 40 +- .../umbraco/create/CreatedPackageTasks.cs | 45 -- .../developer/Packages/editPackage.aspx.cs | 68 ++- 64 files changed, 1543 insertions(+), 1435 deletions(-) delete mode 100644 src/Umbraco.Core/Events/ExportEventArgs.cs create mode 100644 src/Umbraco.Core/Models/Packaging/ActionRunAt.cs create mode 100644 src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs create mode 100644 src/Umbraco.Core/Models/Packaging/PackageDefinition.cs rename src/Umbraco.Core/{Packaging/Models => Models/Packaging}/UninstallationSummary.cs (50%) create mode 100644 src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs create mode 100644 src/Umbraco.Core/Packaging/IPackageCreation.cs rename src/{Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs => Umbraco.Core/Packaging/PackageActionRunner.cs} (58%) create mode 100644 src/Umbraco.Core/Packaging/PackageCreation.cs create mode 100644 src/Umbraco.Core/Services/IEntityXmlSerializer.cs rename src/Umbraco.Core/Services/{ => Implement}/EntityXmlSerializer.cs (70%) create mode 100644 src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 1b77aaa7d6..6133d63377 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Components; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Packaging; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; @@ -56,6 +57,12 @@ namespace Umbraco.Core.Composing.Composers factory.GetInstance>(), factory.GetInstance())); + composition.RegisterUnique(); + + composition.RegisterUnique(); + composition.RegisterUnique(); + + //TODO: These are replaced in the web project - we need to declare them so that // something is wired up, just not sure this is very nice but will work for now. composition.RegisterUnique(); diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index cf67409925..4bed76d86f 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; @@ -161,6 +162,9 @@ namespace Umbraco.Core.Composing internal static PackageActionCollection PackageActions => Factory.GetInstance(); + internal static PackageActionRunner PackageActionRunner + => Factory.GetInstance(); + internal static PropertyValueConverterCollection PropertyValueConverters => Factory.GetInstance(); diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 5e2d44c90d..8c27c23604 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -308,84 +308,45 @@ namespace Umbraco.Core /// Creates the full xml representation for the object and all of it's descendants /// /// to generate xml for - /// + /// /// Xml representation of the passed in - internal static XElement ToDeepXml(this IContent content, IPackagingService packagingService) + internal static XElement ToDeepXml(this IContent content, IEntityXmlSerializer serializer) { - return packagingService.Export(content, true, raiseEvents: false); - } - - - [Obsolete("Use the overload that declares the IPackagingService to use")] - public static XElement ToXml(this IContent content) - { - return Current.Services.PackagingService.Export(content, raiseEvents: false); + return serializer.Serialize(content, false, true); } /// /// Creates the xml representation for the object /// /// to generate xml for - /// + /// /// Xml representation of the passed in - public static XElement ToXml(this IContent content, IPackagingService packagingService) + public static XElement ToXml(this IContent content, IEntityXmlSerializer serializer) { - return packagingService.Export(content, raiseEvents: false); - } - - [Obsolete("Use the overload that declares the IPackagingService to use")] - public static XElement ToXml(this IMedia media) - { - return Current.Services.PackagingService.Export(media, raiseEvents: false); + return serializer.Serialize(content, false, false); } + /// /// Creates the xml representation for the object /// /// to generate xml for - /// + /// /// Xml representation of the passed in - public static XElement ToXml(this IMedia media, IPackagingService packagingService) + public static XElement ToXml(this IMedia media, IEntityXmlSerializer serializer) { - return packagingService.Export(media, raiseEvents: false); + return serializer.Serialize(media); } - /// - /// Creates the full xml representation for the object and all of it's descendants - /// - /// to generate xml for - /// - /// Xml representation of the passed in - internal static XElement ToDeepXml(this IMedia media, IPackagingService packagingService) - { - return packagingService.Export(media, true, raiseEvents: false); - } - - - /// - /// Creates the xml representation for the object - /// - /// to generate xml for - /// - /// Boolean indicating whether the xml should be generated for preview - /// Xml representation of the passed in - public static XElement ToXml(this IContent content, IPackagingService packagingService, bool isPreview) - { - //TODO Do a proper implementation of this - //If current IContent is published we should get latest unpublished version - return content.ToXml(packagingService); - } - - /// /// Creates the xml representation for the object /// /// to generate xml for - /// + /// /// Xml representation of the passed in - public static XElement ToXml(this IMember member, IPackagingService packagingService) + public static XElement ToXml(this IMember member, IEntityXmlSerializer serializer) { - return ((PackagingService)(packagingService)).Export(member); + return serializer.Serialize(member); } #endregion diff --git a/src/Umbraco.Core/Events/ExportEventArgs.cs b/src/Umbraco.Core/Events/ExportEventArgs.cs deleted file mode 100644 index f46cccf05c..0000000000 --- a/src/Umbraco.Core/Events/ExportEventArgs.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Umbraco.Core.Events -{ - public class ExportEventArgs : CancellableObjectEventArgs>, IEquatable> - { - /// - /// Constructor accepting a single entity instance - /// - /// - /// - /// - public ExportEventArgs(TEntity eventObject, XElement xml, bool canCancel) - : base(new List { eventObject }, canCancel) - { - Xml = xml; - } - - /// - /// Constructor accepting a single entity instance - /// and cancellable by default - /// - /// - /// - public ExportEventArgs(TEntity eventObject, string elementName) : base(new List {eventObject}, true) - { - Xml = new XElement(elementName); - } - - protected ExportEventArgs(IEnumerable eventObject, bool canCancel) : base(eventObject, canCancel) - { - } - - protected ExportEventArgs(IEnumerable eventObject) : base(eventObject) - { - } - - /// - /// Returns all entities that were exported during the operation - /// - public IEnumerable ExportedEntities - { - get { return EventObject; } - } - - /// - /// Returns the xml relating to the export event - /// - public XElement Xml { get; private set; } - - public bool Equals(ExportEventArgs other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return base.Equals(other) && Equals(Xml, other.Xml); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((ExportEventArgs) obj); - } - - public override int GetHashCode() - { - unchecked - { - return (base.GetHashCode() * 397) ^ (Xml != null ? Xml.GetHashCode() : 0); - } - } - - public static bool operator ==(ExportEventArgs left, ExportEventArgs right) - { - return Equals(left, right); - } - - public static bool operator !=(ExportEventArgs left, ExportEventArgs right) - { - return !Equals(left, right); - } - } -} diff --git a/src/Umbraco.Core/Models/Packaging/ActionRunAt.cs b/src/Umbraco.Core/Models/Packaging/ActionRunAt.cs new file mode 100644 index 0000000000..0023d4dbed --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/ActionRunAt.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Models.Packaging +{ + public enum ActionRunAt + { + Undefined = 0, + Install, + Uninstall + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index 3eb397d728..39df529300 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -21,23 +21,4 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable Actions { get; set; } public bool PackageInstalled { get; set; } } - - internal static class InstallationSummaryExtentions - { - public static InstallationSummary InitEmpty(this InstallationSummary summary) - { - summary.Actions = new List(); - summary.ContentInstalled = new List(); - summary.ContentTypesInstalled = new List(); - summary.DataTypesInstalled = new List(); - summary.DictionaryItemsInstalled = new List(); - summary.FilesInstalled = new List(); - summary.LanguagesInstalled = new List(); - summary.MacrosInstalled = new List(); - summary.MetaData = new MetaData(); - summary.TemplatesInstalled = new List(); - summary.PackageInstalled = false; - return summary; - } - } } diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs new file mode 100644 index 0000000000..3b969d84dc --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Models.Packaging +{ + internal static class InstallationSummaryExtentions + { + public static InstallationSummary InitEmpty(this InstallationSummary summary) + { + summary.Actions = new List(); + summary.ContentInstalled = new List(); + summary.ContentTypesInstalled = new List(); + summary.DataTypesInstalled = new List(); + summary.DictionaryItemsInstalled = new List(); + summary.FilesInstalled = new List(); + summary.LanguagesInstalled = new List(); + summary.MacrosInstalled = new List(); + summary.MetaData = new MetaData(); + summary.TemplatesInstalled = new List(); + summary.PackageInstalled = false; + return summary; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Packaging/PackageAction.cs b/src/Umbraco.Core/Models/Packaging/PackageAction.cs index e941c5729a..ab7b120eae 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageAction.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageAction.cs @@ -4,13 +4,9 @@ using System.Xml.Linq; namespace Umbraco.Core.Models.Packaging { - public enum ActionRunAt - { - Undefined = 0, - Install, - Uninstall - } - + /// + /// Defines a package action declared within a package manifest + /// [Serializable] [DataContract(IsReference = true)] public class PackageAction diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs new file mode 100644 index 0000000000..783b11235f --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace Umbraco.Core.Models.Packaging +{ + [DataContract(Name = "packageInstance")] + public class PackageDefinition + { + [DataMember(Name = "id")] + public int Id { get; set; } + + //TODO: I don't see why this is necessary + [DataMember(Name = "repositoryGuid")] + public string RepositoryGuid { get; set; } + + [DataMember(Name = "packageGuid")] + public string PackageGuid { get; set; } + + [DataMember(Name = "hasUpdate")] + public bool HasUpdate { get; set; } + + [DataMember(Name = "name")] + [Required] + public string Name { get; set; } = string.Empty; + + [DataMember(Name = "url")] + [Required] + [Url] + public string Url { get; set; } = string.Empty; + + [DataMember(Name = "folder")] + public string Folder { get; set; } = string.Empty; + + [DataMember(Name = "packagePath")] + public string PackagePath { get; set; } = string.Empty; + + [DataMember(Name = "version")] + [Required] + public string Version { get; set; } = string.Empty; + + /// + /// The minimum umbraco version that this package requires + /// + [DataMember(Name = "umbracoVersion")] + public Version UmbracoVersion { get; set; } + + [DataMember(Name = "author")] + [Required] + public string Author { get; set; } = string.Empty; + + [DataMember(Name = "authorUrl")] + [Required] + [Url] + public string AuthorUrl { get; set; } = string.Empty; + + [DataMember(Name = "license")] + public string License { get; set; } = "MIT License"; + + [DataMember(Name = "licenseUrl")] + public string LicenseUrl { get; set; } = "http://opensource.org/licenses/MIT"; + + [DataMember(Name = "readme")] + public string Readme { get; set; } = string.Empty; + + [DataMember(Name = "contentLoadChildNodes")] + public bool ContentLoadChildNodes { get; set; } = false; + + [DataMember(Name = "contentNodeId")] + public string ContentNodeId { get; set; } = string.Empty; + + [DataMember(Name = "macros")] + public List Macros { get; set; } = new List(); + + [DataMember(Name = "languages")] + public List Languages { get; set; } = new List(); + + [DataMember(Name = "dictionaryItems")] + public List DictionaryItems { get; set; } = new List(); + + [DataMember(Name = "templates")] + public List Templates { get; set; } = new List(); + + [DataMember(Name = "documentTypes")] + public List DocumentTypes { get; set; } = new List(); + + [DataMember(Name = "stylesheets")] + public List Stylesheets { get; set; } = new List(); + + [DataMember(Name = "files")] + public List Files { get; set; } = new List(); + + //TODO: Change this to angular view + [DataMember(Name = "loadControl")] + public string LoadControl { get; set; } = string.Empty; + + [DataMember(Name = "actions")] + public string Actions { get; set; } + + [DataMember(Name = "dataTypes")] + public List DataTypes { get; set; } = new List(); + + [DataMember(Name = "iconUrl")] + public string IconUrl { get; set; } = string.Empty; + + } +} diff --git a/src/Umbraco.Core/Packaging/Models/UninstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs similarity index 50% rename from src/Umbraco.Core/Packaging/Models/UninstallationSummary.cs rename to src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs index 1c31283ee8..cfa454f91c 100644 --- a/src/Umbraco.Core/Packaging/Models/UninstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Packaging; -namespace Umbraco.Core.Packaging.Models +namespace Umbraco.Core.Models.Packaging { [Serializable] [DataContract(IsReference = true)] @@ -22,22 +20,4 @@ namespace Umbraco.Core.Packaging.Models public IEnumerable ContentUninstalled { get; set; } public bool PackageUninstalled { get; set; } } - - internal static class UninstallationSummaryExtentions - { - public static UninstallationSummary InitEmpty(this UninstallationSummary summary) - { - summary.ContentUninstalled = new List(); - summary.ContentTypesUninstalled = new List(); - summary.DataTypesUninstalled = new List(); - summary.DictionaryItemsUninstalled = new List(); - summary.FilesUninstalled = new List(); - summary.LanguagesUninstalled = new List(); - summary.MacrosUninstalled = new List(); - summary.MetaData = new MetaData(); - summary.TemplatesUninstalled = new List(); - summary.PackageUninstalled = false; - return summary; - } - } } diff --git a/src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs b/src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs new file mode 100644 index 0000000000..688b78fa1f --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Models.Packaging +{ + internal static class UninstallationSummaryExtentions + { + public static UninstallationSummary InitEmpty(this UninstallationSummary summary) + { + summary.ContentUninstalled = new List(); + summary.ContentTypesUninstalled = new List(); + summary.DataTypesUninstalled = new List(); + summary.DictionaryItemsUninstalled = new List(); + summary.FilesUninstalled = new List(); + summary.LanguagesUninstalled = new List(); + summary.MacrosUninstalled = new List(); + summary.MetaData = new MetaData(); + summary.TemplatesUninstalled = new List(); + summary.PackageUninstalled = false; + return summary; + } + } +} diff --git a/src/Umbraco.Core/Packaging/IPackageCreation.cs b/src/Umbraco.Core/Packaging/IPackageCreation.cs new file mode 100644 index 0000000000..35397299a7 --- /dev/null +++ b/src/Umbraco.Core/Packaging/IPackageCreation.cs @@ -0,0 +1,22 @@ +using Umbraco.Core.Models.Packaging; + +namespace Umbraco.Core.Packaging +{ + /// + /// Creates packages + /// + public interface IPackageCreation + { + /// + /// Persists a package definition to storage + /// + /// + void SavePackageDefinition(PackageDefinition definition); + + /// + /// Creates the package file and returns it's physical path + /// + /// + string ExportPackageDefinition(PackageDefinition definition); + } +} diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 1d0d46355c..6dc4f0fd4e 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -5,6 +5,9 @@ namespace Umbraco.Core.Packaging { internal interface IPackageInstallation { + //fixme: The reason why this isn't used currently is because package installation needs to be done in phases since + // there are app domain reboots involved so a single method cannot be used. This needs to either be split into several + // methods or return an object with a callback to proceed to the next step. InstallationSummary InstallPackage(string packageFilePath, int userId); MetaData GetMetaData(string packageFilePath); PreInstallWarnings GetPreInstallWarnings(string packageFilePath); diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs b/src/Umbraco.Core/Packaging/PackageActionRunner.cs similarity index 58% rename from src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs rename to src/Umbraco.Core/Packaging/PackageActionRunner.cs index bfd1030d85..c7545bdae8 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageActions.cs +++ b/src/Umbraco.Core/Packaging/PackageActionRunner.cs @@ -1,17 +1,24 @@ using System; using System.Xml; -using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core._Legacy.PackageActions; -namespace Umbraco.Web._Legacy.Packager.PackageInstance +namespace Umbraco.Core.Packaging { /// /// Package actions are executed on packge install / uninstall. /// - public class PackageAction + public sealed class PackageActionRunner { + private readonly ILogger _logger; + private readonly PackageActionCollection _packageActions; + + public PackageActionRunner(ILogger logger, PackageActionCollection packageActions) + { + _logger = logger; + _packageActions = packageActions; + } /// /// Runs the package action with the specified action alias. @@ -19,22 +26,19 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance /// Name of the package. /// The action alias. /// The action XML. - public static void RunPackageAction(string packageName, string actionAlias, XmlNode actionXml) + public void RunPackageAction(string packageName, string actionAlias, XmlNode actionXml) { - foreach (var ipa in Current.PackageActions) + foreach (var ipa in _packageActions) { try { if (ipa.Alias() == actionAlias) - { - ipa.Execute(packageName, actionXml); - } } catch (Exception ex) { - Current.Logger.Error(ex, "Error loading package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); + _logger.Error(ex, "Error loading package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } } @@ -45,22 +49,18 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance /// Name of the package. /// The action alias. /// The action XML. - public static void UndoPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) + public void UndoPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) { - - foreach (IPackageAction ipa in Current.PackageActions) + foreach (var ipa in _packageActions) { try { if (ipa.Alias() == actionAlias) - { - ipa.Undo(packageName, actionXml); - } } catch (Exception ex) { - Current.Logger.Error(ex, "Error undoing package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); + _logger.Error(ex, "Error undoing package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } } diff --git a/src/Umbraco.Core/Packaging/PackageCreation.cs b/src/Umbraco.Core/Packaging/PackageCreation.cs new file mode 100644 index 0000000000..615b844101 --- /dev/null +++ b/src/Umbraco.Core/Packaging/PackageCreation.cs @@ -0,0 +1,564 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Xml.Linq; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Services; +using File = System.IO.File; + +namespace Umbraco.Core.Packaging +{ + internal class PackageCreation : IPackageCreation + { + private readonly IContentService _contentService; + private readonly IContentTypeService _contentTypeService; + private readonly IDataTypeService _dataTypeService; + private readonly IFileService _fileService; + private readonly IMacroService _macroService; + private readonly ILocalizationService _languageService; + private readonly IEntityXmlSerializer _serializer; + private readonly ILogger _logger; + + public PackageCreation(IContentService contentService, IContentTypeService contentTypeService, + IDataTypeService dataTypeService, IFileService fileService, IMacroService macroService, + ILocalizationService languageService, + IEntityXmlSerializer serializer, ILogger logger) + { + _contentService = contentService; + _contentTypeService = contentTypeService; + _dataTypeService = dataTypeService; + _fileService = fileService; + _macroService = macroService; + _languageService = languageService; + _serializer = serializer; + _logger = logger; + } + + public static string CreatedPackagesFile => SystemDirectories.Packages + IOHelper.DirSepChar + "createdPackages.config"; + + public void SavePackageDefinition(PackageDefinition definition) + { + if (definition == null) throw new ArgumentNullException(nameof(definition)); + + var packagesXml = EnsureStorage(out var packagesFile); + + if (definition.Id == default) + { + //need to gen an id and persist + // Find max id + var maxId = packagesXml.Root.Elements("package").Max(x => x.AttributeValue("id")); + var newId = maxId + 1; + definition.Id = newId; + definition.PackageGuid = Guid.NewGuid().ToString(); + definition.Folder = Guid.NewGuid().ToString(); + var packageXml = PackageDefinitionToXml(definition); + packagesXml.Add(packageXml); + } + else + { + //existing + var packageXml = packagesXml.Root.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == definition.Id); + if (packageXml == null) + throw new InvalidOperationException($"The package with id {definition.Id} was not found"); + + var updatedXml = PackageDefinitionToXml(definition); + packageXml.ReplaceWith(updatedXml); + } + + packagesXml.Save(packagesFile); + } + + public string ExportPackageDefinition(PackageDefinition definition) + { + if (definition.Id == default) throw new ArgumentException("The package definition does not have an ID, it must be saved before being exported"); + if (definition.PackageGuid.IsNullOrWhiteSpace()) throw new ArgumentException("the package definition does not have a GUID, it must be saved before being exported"); + + //Create a folder for building this package + var temporaryPath = IOHelper.MapPath(SystemDirectories.Data + "/TEMP/PackageFiles/" + definition.Folder); + if (Directory.Exists(temporaryPath) == false) + Directory.CreateDirectory(temporaryPath); + + try + { + //Init package file + var packageManifest = CreatePackageManifest(out var manifestRoot, out var filesXml); + + //Info section + packageManifest.Add(GetPackageInfoXml(definition)); + + PackageDocumentsAndTags(definition, manifestRoot); + PackageDocumentTypes(definition, manifestRoot); + PackageTemplates(definition, manifestRoot); + PackageStylesheets(definition, manifestRoot); + PackageMacros(definition, manifestRoot, filesXml, temporaryPath); + PackageDictionaryItems(definition, manifestRoot); + PackageLanguages(definition, manifestRoot); + PackageDataTypes(definition, manifestRoot); + + //Files + foreach (var fileName in definition.Files) + AppendFileToManifest(fileName, temporaryPath, filesXml); + + //Load control on install... + if (!string.IsNullOrEmpty(definition.LoadControl)) + { + var control = new XElement("control", definition.LoadControl); + AppendFileToManifest(definition.LoadControl, temporaryPath, filesXml); + manifestRoot.Add(control); + } + + //Actions + if (string.IsNullOrEmpty(definition.Actions) == false) + { + var actionsXml = new XElement("Actions"); + try + { + actionsXml.Add(XElement.Parse(definition.Actions)); + manifestRoot.Add(actionsXml); + } + catch (Exception e) + { + _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); + } + } + + var manifestFileName = temporaryPath + "/package.xml"; + + if (File.Exists(manifestFileName)) + File.Delete(manifestFileName); + + packageManifest.Save(manifestFileName); + + // check if there's a packages directory below media + var packagesDirectory = SystemDirectories.Media + "/created-packages"; + if (Directory.Exists(IOHelper.MapPath(packagesDirectory)) == false) + Directory.CreateDirectory(IOHelper.MapPath(packagesDirectory)); + + var packPath = packagesDirectory + "/" + (definition.Name + "_" + definition.Version).Replace(' ', '_') + ".zip"; + ZipPackage(temporaryPath, IOHelper.MapPath(packPath)); + + return packPath; + } + finally + { + //Clean up + Directory.Delete(temporaryPath, true); + } + } + + private void PackageDataTypes(PackageDefinition definition, XContainer manifestRoot) + { + var dataTypes = new XElement("DataTypes"); + foreach (var dtId in definition.DataTypes) + { + if (!int.TryParse(dtId, out var outInt)) continue; + var dataType = _dataTypeService.GetDataType(outInt); + if (dataType == null) continue; + dataTypes.Add(_serializer.Serialize(dataType)); + } + manifestRoot.Add(dataTypes); + } + + private void PackageLanguages(PackageDefinition definition, XContainer manifestRoot) + { + var languages = new XElement("Languages"); + foreach (var langId in definition.Languages) + { + if (!int.TryParse(langId, out var outInt)) continue; + var lang = _languageService.GetLanguageById(outInt); + if (lang == null) continue; + languages.Add(_serializer.Serialize(lang)); + } + manifestRoot.Add(languages); + } + + private void PackageDictionaryItems(PackageDefinition definition, XContainer manifestRoot) + { + var dictionaryItems = new XElement("DictionaryItems"); + foreach (var dictionaryId in definition.DictionaryItems) + { + if (!int.TryParse(dictionaryId, out var outInt)) continue; + var di = _languageService.GetDictionaryItemById(outInt); + if (di == null) continue; + dictionaryItems.Add(_serializer.Serialize(di, false)); + } + manifestRoot.Add(dictionaryItems); + } + + private void PackageMacros(PackageDefinition definition, XContainer manifestRoot, XContainer filesXml, string temporaryPath) + { + var macros = new XElement("Macros"); + foreach (var macroId in definition.Macros) + { + if (!int.TryParse(macroId, out var outInt)) continue; + + var macroXml = GetMacroXml(outInt, out var macro); + if (macroXml == null) continue; + macros.Add(macroXml); + //if the macro has a file copy it to the manifest + if (!string.IsNullOrEmpty(macro.MacroSource)) + AppendFileToManifest(macro.MacroSource, temporaryPath, filesXml); + } + manifestRoot.Add(macros); + } + + private void PackageStylesheets(PackageDefinition definition, XContainer manifestRoot) + { + var stylesheetsXml = new XElement("Stylesheets"); + foreach (var stylesheetName in definition.Stylesheets) + { + if (stylesheetName.IsNullOrWhiteSpace()) continue; + var xml = GetStylesheetXml(stylesheetName, true); + if (xml != null) + stylesheetsXml.Add(xml); + } + manifestRoot.Add(stylesheetsXml); + } + + private void PackageTemplates(PackageDefinition definition, XContainer manifestRoot) + { + var templatesXml = new XElement("Templates"); + foreach (var templateId in definition.Templates) + { + if (!int.TryParse(templateId, out var outInt)) continue; + var template = _fileService.GetTemplate(outInt); + if (template == null) continue; + templatesXml.Add(_serializer.Serialize(template)); + } + manifestRoot.Add(templatesXml); + } + + private void PackageDocumentTypes(PackageDefinition definition, XContainer manifestRoot) + { + var contentTypes = new HashSet(); + var docTypesXml = new XElement("DocumentTypes"); + foreach (var dtId in definition.DocumentTypes) + { + if (!int.TryParse(dtId, out var outInt)) continue; + var contentType = _contentTypeService.Get(outInt); + if (contentType == null) continue; + AddDocumentType(contentType, contentTypes); + } + foreach (var contentType in contentTypes) + docTypesXml.Add(_serializer.Serialize(contentType)); + + manifestRoot.Add(docTypesXml); + } + + private void PackageDocumentsAndTags(PackageDefinition definition, XContainer manifestRoot) + { + //Documents and tags + if (string.IsNullOrEmpty(definition.ContentNodeId) == false && int.TryParse(definition.ContentNodeId, out var contentNodeId)) + { + if (contentNodeId > 0) + { + //load content from umbraco. + var content = _contentService.GetById(contentNodeId); + if (content != null) + { + var contentXml = definition.ContentLoadChildNodes ? content.ToDeepXml(_serializer) : content.ToXml(_serializer); + + //Create the Documents/DocumentSet node + + manifestRoot.Add( + new XElement("Documents", + new XElement("DocumentSet", + new XAttribute("importMode", "root"), + contentXml))); + + //TODO: I guess tags has been broken for a very long time for packaging, we should get this working again sometime + ////Create the TagProperties node - this is used to store a definition for all + //// document properties that are tags, this ensures that we can re-import tags properly + //XmlNode tagProps = new XElement("TagProperties"); + + ////before we try to populate this, we'll do a quick lookup to see if any of the documents + //// being exported contain published tags. + //var allExportedIds = documents.SelectNodes("//@id").Cast() + // .Select(x => x.Value.TryConvertTo()) + // .Where(x => x.Success) + // .Select(x => x.Result) + // .ToArray(); + //var allContentTags = new List(); + //foreach (var exportedId in allExportedIds) + //{ + // allContentTags.AddRange( + // Current.Services.TagService.GetTagsForEntity(exportedId)); + //} + + ////This is pretty round-about but it works. Essentially we need to get the properties that are tagged + //// but to do that we need to lookup by a tag (string) + //var allTaggedEntities = new List(); + //foreach (var group in allContentTags.Select(x => x.Group).Distinct()) + //{ + // allTaggedEntities.AddRange( + // Current.Services.TagService.GetTaggedContentByTagGroup(group)); + //} + + ////Now, we have all property Ids/Aliases and their referenced document Ids and tags + //var allExportedTaggedEntities = allTaggedEntities.Where(x => allExportedIds.Contains(x.EntityId)) + // .DistinctBy(x => x.EntityId) + // .OrderBy(x => x.EntityId); + + //foreach (var taggedEntity in allExportedTaggedEntities) + //{ + // foreach (var taggedProperty in taggedEntity.TaggedProperties.Where(x => x.Tags.Any())) + // { + // XmlNode tagProp = new XElement("TagProperty"); + // var docId = packageManifest.CreateAttribute("docId", ""); + // docId.Value = taggedEntity.EntityId.ToString(CultureInfo.InvariantCulture); + // tagProp.Attributes.Append(docId); + + // var propertyAlias = packageManifest.CreateAttribute("propertyAlias", ""); + // propertyAlias.Value = taggedProperty.PropertyTypeAlias; + // tagProp.Attributes.Append(propertyAlias); + + // var group = packageManifest.CreateAttribute("group", ""); + // group.Value = taggedProperty.Tags.First().Group; + // tagProp.Attributes.Append(group); + + // tagProp.AppendChild(packageManifest.CreateCDataSection( + // JsonConvert.SerializeObject(taggedProperty.Tags.Select(x => x.Text).ToArray()))); + + // tagProps.AppendChild(tagProp); + // } + //} + + //manifestRoot.Add(tagProps); + } + } + } + } + + /// + /// Zips the package. + /// + /// The path. + /// The save path. + private static void ZipPackage(string path, string savePath) + { + ZipFile.CreateFromDirectory(path, savePath); + } + + /// + /// Appends a file to package manifest and copies the file to the correct folder. + /// + /// The path. + /// The package directory. + /// The files xml node + private static void AppendFileToManifest(string path, string packageDirectory, XContainer filesXml) + { + if (!path.StartsWith("~/") && !path.StartsWith("/")) + path = "~/" + path; + + var serverPath = IOHelper.MapPath(path); + + if (File.Exists(serverPath)) + AppendFileXml(new FileInfo(serverPath), path, packageDirectory, filesXml); + else if (Directory.Exists(serverPath)) + ProcessDirectory(new DirectoryInfo(serverPath), path, packageDirectory, filesXml); + } + + //Process files in directory and add them to package + private static void ProcessDirectory(DirectoryInfo directory, string dirPath, string packageDirectory, XContainer filesXml) + { + if (directory == null) throw new ArgumentNullException(nameof(directory)); + if (string.IsNullOrWhiteSpace(packageDirectory)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(packageDirectory)); + if (string.IsNullOrWhiteSpace(dirPath)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(dirPath)); + if (!directory.Exists) return; + + foreach (var file in directory.GetFiles()) + AppendFileXml(new FileInfo(Path.Combine(directory.FullName, file.Name)), dirPath + "/" + file.Name, packageDirectory, filesXml); + + foreach (var dir in directory.GetDirectories()) + ProcessDirectory(dir, dirPath + "/" + dir.Name, packageDirectory, filesXml); + } + + private static void AppendFileXml(FileInfo file, string filePath, string packageDirectory, XContainer filesXml) + { + if (file == null) throw new ArgumentNullException(nameof(file)); + if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(filePath)); + if (string.IsNullOrWhiteSpace(packageDirectory)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(packageDirectory)); + + var orgPath = filePath.Substring(0, (filePath.LastIndexOf('/'))); + var orgName = filePath.Substring((filePath.LastIndexOf('/') + 1)); + var newFileName = orgName; + + if (File.Exists(packageDirectory.EnsureEndsWith('/') + orgName)) + newFileName = Guid.NewGuid() + "_" + newFileName; + + //Copy file to directory for zipping... + File.Copy(file.FullName, packageDirectory + "/" + newFileName, true); + + filesXml.Add(new XElement("file", + new XElement("guid", newFileName), + new XElement("orgPath", orgPath == "" ? "/" : orgPath), + new XElement("orgName", orgName))); + } + + private XElement GetMacroXml(int macroId, out IMacro macro) + { + macro = _macroService.GetById(macroId); + if (macro == null) return null; + var xml = _serializer.Serialize(macro); + return xml; + } + + /// + /// Converts a umbraco stylesheet to a package xml node + /// + /// The name of the stylesheet. + /// if set to true [incluce properties]. + /// + private XElement GetStylesheetXml(string name, bool includeProperties) + { + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); +; + var sts = _fileService.GetStylesheetByName(name); + if (sts == null) return null; + var stylesheetXml = new XElement("Stylesheet"); + stylesheetXml.Add(new XElement("Name", sts.Alias)); + stylesheetXml.Add(new XElement("FileName", sts.Name)); + stylesheetXml.Add(new XElement("Content", new XCData(sts.Content))); + + if (!includeProperties) return stylesheetXml; + + var properties = new XElement("Properties"); + foreach (var ssP in sts.Properties) + { + var property = new XElement("Property"); + property.Add(new XElement("Name", ssP.Name)); + property.Add(new XElement("Alias", ssP.Alias)); + property.Add(new XElement("Value", ssP.Value)); + } + stylesheetXml.Add(properties); + return stylesheetXml; + } + + private void AddDocumentType(IContentType dt, HashSet dtl) + { + if (dt.ParentId > 0) + { + var parent = _contentTypeService.Get(dt.ParentId); + if (parent != null) // could be a container + AddDocumentType(parent, dtl); + } + + if (!dtl.Contains(dt)) + dtl.Add(dt); + } + + private static XElement GetPackageInfoXml(PackageDefinition definition) + { + var info = new XElement("info"); + + //Package info + var package = new XElement("package"); + package.Add(new XElement("name", definition.Name)); + package.Add(new XElement("version", definition.Version)); + package.Add(new XElement("iconUrl", definition.IconUrl)); + + var license = new XElement("license", definition.License); + license.Add(new XAttribute("url", definition.LicenseUrl)); + package.Add(license); + + package.Add(new XElement("url", definition.Url)); + + var requirements = new XElement("requirements"); + + requirements.Add(new XElement("major", definition.UmbracoVersion == null ? UmbracoVersion.SemanticVersion.Major.ToInvariantString() : definition.UmbracoVersion.Major.ToInvariantString())); + requirements.Add(new XElement("minor", definition.UmbracoVersion == null ? UmbracoVersion.SemanticVersion.Minor.ToInvariantString() : definition.UmbracoVersion.Minor.ToInvariantString())); + requirements.Add(new XElement("patch", definition.UmbracoVersion == null ? UmbracoVersion.SemanticVersion.Patch.ToInvariantString() : definition.UmbracoVersion.Build.ToInvariantString())); + + if (definition.UmbracoVersion != null) + requirements.Add(new XAttribute("type", "strict")); + + package.Add(requirements); + info.Add(package); + + //Author + var author = new XElement("author", ""); + author.Add(new XElement("name", definition.Author)); + author.Add(new XElement("website", definition.AuthorUrl)); + info.Add(author); + + info.Add(new XElement("readme", new XCData(definition.Readme))); + + return info; + } + + private static XDocument CreatePackageManifest(out XElement root, out XElement files) + { + files = new XElement("files"); + root = new XElement("umbPackage", files); + var packageManifest = new XDocument(); + return packageManifest; + } + + private static XDocument EnsureStorage(out string packagesFile) + { + var packagesFolder = IOHelper.MapPath(SystemDirectories.Packages); + //ensure it exists + Directory.CreateDirectory(packagesFolder); + + packagesFile = IOHelper.MapPath(CreatedPackagesFile); + if (!File.Exists(packagesFile)) + { + var xml = new XDocument(new XElement("packages")); + xml.Save(packagesFile); + } + + var packagesXml = XDocument.Load(packagesFile); + return packagesXml; + } + + private static XElement PackageDefinitionToXml(PackageDefinition def) + { + var packageXml = new XElement("package", + new XAttribute("id", def.Id), + new XAttribute("version", def.Version), + new XAttribute("url", def.Url), + new XAttribute("name", def.Name), + new XAttribute("folder", def.Folder), //fixme: What is this? + new XAttribute("packagepath", def.PackagePath), + new XAttribute("repositoryGuid", def.RepositoryGuid), + new XAttribute("iconUrl", def.IconUrl), + new XAttribute("umbVersion", def.UmbracoVersion), + new XAttribute("packageGuid", def.PackageGuid), + new XAttribute("hasUpdate", def.HasUpdate), //fixme: What is this? + + new XElement("license", + new XCData(def.License), + new XAttribute("url", def.LicenseUrl)), + + new XElement("author", + new XCData(def.Author), + new XAttribute("url", def.AuthorUrl)), + + new XElement("readme", def.Readme), + new XElement("actions", def.Actions), + new XElement("datatypes", string.Join(",", def.DataTypes)), + + new XElement("content", + new XAttribute("nodeId", def.ContentNodeId), + new XAttribute("loadChildNodes", def.ContentLoadChildNodes)), + + new XElement("templates", string.Join(",", def.Templates)), + new XElement("stylesheets", string.Join(",", def.Stylesheets)), + new XElement("documentTypes", string.Join(",", def.DocumentTypes)), + new XElement("macros", string.Join(",", def.Macros)), + new XElement("files", string.Join(",", def.Files)), + new XElement("languages", string.Join(",", def.Languages)), + new XElement("dictionaryitems", string.Join(",", def.DictionaryItems)), + new XElement("loadcontrol", "")); //fixme: no more loadcontrol, needs to be an angular view + + return packageXml; + } + + } +} diff --git a/src/Umbraco.Core/Services/IEntityXmlSerializer.cs b/src/Umbraco.Core/Services/IEntityXmlSerializer.cs new file mode 100644 index 0000000000..405fc47c3a --- /dev/null +++ b/src/Umbraco.Core/Services/IEntityXmlSerializer.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Xml.Linq; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Services +{ + /// + /// Serializes entities to XML + /// + public interface IEntityXmlSerializer + { + /// + /// Exports an IContent item as an XElement. + /// + XElement Serialize(IContent content, + bool published, + bool withDescendants = false) //fixme take care of usage! only used for the packager + ; + + /// + /// Exports an IMedia item as an XElement. + /// + XElement Serialize( + IMedia media, + bool withDescendants = false); + + /// + /// Exports an IMember item as an XElement. + /// + XElement Serialize(IMember member); + + /// + /// Exports a list of Data Types + /// + /// List of data types to export + /// containing the xml representation of the IDataTypeDefinition objects + XElement Serialize(IEnumerable dataTypeDefinitions); + + XElement Serialize(IDataType dataType); + + /// + /// Exports a list of items to xml as an + /// + /// List of dictionary items to export + /// Optional boolean indicating whether or not to include children + /// containing the xml representation of the IDictionaryItem objects + XElement Serialize(IEnumerable dictionaryItem, bool includeChildren = true); + + /// + /// Exports a single item to xml as an + /// + /// Dictionary Item to export + /// Optional boolean indicating whether or not to include children + /// containing the xml representation of the IDictionaryItem object + XElement Serialize(IDictionaryItem dictionaryItem, bool includeChildren); + + XElement Serialize(Stylesheet stylesheet); + + /// + /// Exports a list of items to xml as an + /// + /// List of Languages to export + /// containing the xml representation of the ILanguage objects + XElement Serialize(IEnumerable languages); + + XElement Serialize(ILanguage language); + XElement Serialize(ITemplate template); + + /// + /// Exports a list of items to xml as an + /// + /// + /// + XElement Serialize(IEnumerable templates); + + XElement Serialize(IMediaType mediaType); + + /// + /// Exports a list of items to xml as an + /// + /// Macros to export + /// containing the xml representation of the IMacro objects + XElement Serialize(IEnumerable macros); + + XElement Serialize(IMacro macro); + XElement Serialize(IContentType contentType); + } +} diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index ceab6e94bf..585ea36aa9 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -2,11 +2,21 @@ using System.Collections.Generic; using System.Xml.Linq; using Umbraco.Core.Models; +using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Packaging; namespace Umbraco.Core.Services { public interface IPackagingService : IService { + #region Package Creation + /// + /// Persists a package definition to storage + /// + /// + void SavePackageDefinition(PackageDefinition definition); + #endregion + /// /// Imports and saves package xml as /// @@ -80,114 +90,6 @@ namespace Umbraco.Core.Services /// An enumrable list of generated Templates IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true); - /// - /// Exports an to xml as an - /// - /// ContentType to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ContentType item - XElement Export(IContentType contentType, bool raiseEvents = true); - - /// - /// Exports an item to xml as an - /// - /// Content to export - /// Optional parameter indicating whether to include descendents - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the Content object - XElement Export(IContent content, bool deep = false, bool raiseEvents = true); - - /// - /// Exports an item to xml as an - /// - /// Media to export - /// Optional parameter indicating whether to include descendents - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the Media object - XElement Export(IMedia media, bool deep = false, bool raiseEvents = true); - - /// - /// Exports a list of items to xml as an - /// - /// List of Languages to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the Language object - XElement Export(IEnumerable languages, bool raiseEvents = true); - - /// - /// Exports a single item to xml as an - /// - /// Language to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the Language object - XElement Export(ILanguage language, bool raiseEvents = true); - - /// - /// Exports a list of items to xml as an - /// - /// List of dictionary items to export - /// Optional boolean indicating whether or not to include children - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDictionaryItem objects - XElement Export(IEnumerable dictionaryItem, bool includeChildren = true, bool raiseEvents = true); - - /// - /// Exports a single item to xml as an - /// - /// Dictionary Item to export - /// Optional boolean indicating whether or not to include children - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDictionaryItem object - XElement Export(IDictionaryItem dictionaryItem, bool includeChildren, bool raiseEvents = true); - - /// - /// Exports a list of Data Types - /// - /// List of data types to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDataTypeDefinition objects - XElement Export(IEnumerable dataTypeDefinitions, bool raiseEvents = true); - - /// - /// Exports a single Data Type - /// - /// Data type to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDataTypeDefinition object - XElement Export(IDataType dataType, bool raiseEvents = true); - - /// - /// Exports a list of items to xml as an - /// - /// List of Templates to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ITemplate objects - XElement Export(IEnumerable templates, bool raiseEvents = true); - - /// - /// Exports a single item to xml as an - /// - /// Template to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ITemplate object - XElement Export(ITemplate template, bool raiseEvents = true); - - /// - /// Exports a list of items to xml as an - /// - /// Macros to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IMacro objects - XElement Export(IEnumerable macros, bool raiseEvents = true); - - /// - /// Exports a single item to xml as an - /// - /// Macro to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IMacro object - XElement Export(IMacro macro, bool raiseEvents = true); - /// /// This will fetch an Umbraco package file from the package repository and return the relative file path to the downloaded package file /// diff --git a/src/Umbraco.Core/Services/Implement/EntityService.cs b/src/Umbraco.Core/Services/Implement/EntityService.cs index 4a3db29940..37b569b814 100644 --- a/src/Umbraco.Core/Services/Implement/EntityService.cs +++ b/src/Umbraco.Core/Services/Implement/EntityService.cs @@ -258,6 +258,9 @@ namespace Umbraco.Core.Services.Implement public virtual IEnumerable GetAll(UmbracoObjectTypes objectType, params int[] ids) { var entityType = objectType.GetClrType(); + if (entityType == null) + throw new NotSupportedException($"Type \"{objectType}\" is not supported here."); + GetGetters(entityType); using (ScopeProvider.CreateScope(autoComplete: true)) diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs similarity index 70% rename from src/Umbraco.Core/Services/EntityXmlSerializer.cs rename to src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index 5b64584dc6..e90d894fcd 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -7,49 +7,61 @@ using System.Xml.Linq; using Newtonsoft.Json; using Umbraco.Core.Composing; using Umbraco.Core.Models; -using Umbraco.Core.PropertyEditors; using Umbraco.Core.Strings; -namespace Umbraco.Core.Services +namespace Umbraco.Core.Services.Implement { - //TODO: Move the rest of the logic for the PackageService.Export methods to here! - /// - /// A helper class to serialize entities to XML + /// Serializes entities to XML /// - internal class EntityXmlSerializer + internal class EntityXmlSerializer : IEntityXmlSerializer { - /// - /// Exports an IContent item as an XElement. - /// - public static XElement Serialize( + private readonly IContentTypeService _contentTypeService; + private readonly IMediaService _mediaService; + private readonly IContentService _contentService; + private readonly IDataTypeService _dataTypeService; + private readonly IUserService _userService; + private readonly ILocalizationService _localizationService; + private readonly IEnumerable _urlSegmentProviders; + + public EntityXmlSerializer( IContentService contentService, + IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, - IEnumerable urlSegmentProviders, - IContent content, + IContentTypeService contentTypeService, + IEnumerable urlSegmentProviders) + { + _contentTypeService = contentTypeService; + _mediaService = mediaService; + _contentService = contentService; + _dataTypeService = dataTypeService; + _userService = userService; + _localizationService = localizationService; + _urlSegmentProviders = urlSegmentProviders; + } + + /// + /// Exports an IContent item as an XElement. + /// + public XElement Serialize(IContent content, bool published, bool withDescendants = false) //fixme take care of usage! only used for the packager { - if (contentService == null) throw new ArgumentNullException(nameof(contentService)); - if (dataTypeService == null) throw new ArgumentNullException(nameof(dataTypeService)); - if (userService == null) throw new ArgumentNullException(nameof(userService)); - if (localizationService == null) throw new ArgumentNullException(nameof(localizationService)); if (content == null) throw new ArgumentNullException(nameof(content)); - if (urlSegmentProviders == null) throw new ArgumentNullException(nameof(urlSegmentProviders)); // nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias); var nodeName = content.ContentType.Alias.ToSafeAliasWithForcingCheck(); - var xml = SerializeContentBase(dataTypeService, localizationService, content, content.GetUrlSegment(urlSegmentProviders), nodeName, published); + var xml = SerializeContentBase(content, content.GetUrlSegment(_urlSegmentProviders), nodeName, published); xml.Add(new XAttribute("nodeType", content.ContentType.Id)); xml.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias)); - xml.Add(new XAttribute("creatorName", content.GetCreatorProfile(userService)?.Name ?? "??")); + xml.Add(new XAttribute("creatorName", content.GetCreatorProfile(_userService)?.Name ?? "??")); //xml.Add(new XAttribute("creatorID", content.CreatorId)); - xml.Add(new XAttribute("writerName", content.GetWriterProfile(userService)?.Name ?? "??")); + xml.Add(new XAttribute("writerName", content.GetWriterProfile(_userService)?.Name ?? "??")); xml.Add(new XAttribute("writerID", content.WriterId)); xml.Add(new XAttribute("template", content.Template?.Id.ToString(CultureInfo.InvariantCulture) ?? "0")); @@ -63,8 +75,8 @@ namespace Umbraco.Core.Services var total = long.MaxValue; while(page * pageSize < total) { - var children = contentService.GetPagedChildren(content.Id, page++, pageSize, out total); - SerializeChildren(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, children, xml, published); + var children = _contentService.GetPagedChildren(content.Id, page++, pageSize, out total); + SerializeChildren(children, xml, published); } } @@ -75,34 +87,29 @@ namespace Umbraco.Core.Services /// /// Exports an IMedia item as an XElement. /// - public static XElement Serialize( - IMediaService mediaService, - IDataTypeService dataTypeService, - IUserService userService, - ILocalizationService localizationService, - IEnumerable urlSegmentProviders, + public XElement Serialize( IMedia media, bool withDescendants = false) { - if (mediaService == null) throw new ArgumentNullException(nameof(mediaService)); - if (dataTypeService == null) throw new ArgumentNullException(nameof(dataTypeService)); - if (userService == null) throw new ArgumentNullException(nameof(userService)); - if (localizationService == null) throw new ArgumentNullException(nameof(localizationService)); + if (_mediaService == null) throw new ArgumentNullException(nameof(_mediaService)); + if (_dataTypeService == null) throw new ArgumentNullException(nameof(_dataTypeService)); + if (_userService == null) throw new ArgumentNullException(nameof(_userService)); + if (_localizationService == null) throw new ArgumentNullException(nameof(_localizationService)); if (media == null) throw new ArgumentNullException(nameof(media)); - if (urlSegmentProviders == null) throw new ArgumentNullException(nameof(urlSegmentProviders)); + if (_urlSegmentProviders == null) throw new ArgumentNullException(nameof(_urlSegmentProviders)); // nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias); var nodeName = media.ContentType.Alias.ToSafeAliasWithForcingCheck(); const bool published = false; // always false for media - var xml = SerializeContentBase(dataTypeService, localizationService, media, media.GetUrlSegment(urlSegmentProviders), nodeName, published); + var xml = SerializeContentBase(media, media.GetUrlSegment(_urlSegmentProviders), nodeName, published); xml.Add(new XAttribute("nodeType", media.ContentType.Id)); xml.Add(new XAttribute("nodeTypeAlias", media.ContentType.Alias)); //xml.Add(new XAttribute("creatorName", media.GetCreatorProfile(userService).Name)); //xml.Add(new XAttribute("creatorID", media.CreatorId)); - xml.Add(new XAttribute("writerName", media.GetWriterProfile(userService)?.Name ?? string.Empty)); + xml.Add(new XAttribute("writerName", media.GetWriterProfile(_userService)?.Name ?? string.Empty)); xml.Add(new XAttribute("writerID", media.WriterId)); //xml.Add(new XAttribute("template", 0)); // no template for media @@ -114,8 +121,8 @@ namespace Umbraco.Core.Services var total = long.MaxValue; while (page * pageSize < total) { - var children = mediaService.GetPagedChildren(media.Id, page++, pageSize, out total); - SerializeChildren(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, children, xml); + var children = _mediaService.GetPagedChildren(media.Id, page++, pageSize, out total); + SerializeChildren(children, xml); } } @@ -125,16 +132,13 @@ namespace Umbraco.Core.Services /// /// Exports an IMember item as an XElement. /// - public static XElement Serialize( - IDataTypeService dataTypeService, - ILocalizationService localizationService, - IMember member) + public XElement Serialize(IMember member) { // nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias); var nodeName = member.ContentType.Alias.ToSafeAliasWithForcingCheck(); const bool published = false; // always false for member - var xml = SerializeContentBase(dataTypeService, localizationService, member, "", nodeName, published); + var xml = SerializeContentBase(member, "", nodeName, published); xml.Add(new XAttribute("nodeType", member.ContentType.Id)); xml.Add(new XAttribute("nodeTypeAlias", member.ContentType.Alias)); @@ -148,7 +152,22 @@ namespace Umbraco.Core.Services return xml; } - public XElement Serialize(IDataTypeService dataTypeService, IDataType dataType) + /// + /// Exports a list of Data Types + /// + /// List of data types to export + /// containing the xml representation of the IDataTypeDefinition objects + public XElement Serialize(IEnumerable dataTypeDefinitions) + { + var container = new XElement("DataTypes"); + foreach (var dataTypeDefinition in dataTypeDefinitions) + { + container.Add(Serialize(dataTypeDefinition)); + } + return container; + } + + public XElement Serialize(IDataType dataType) { var xml = new XElement("DataType"); xml.Add(new XAttribute("Name", dataType.Name)); @@ -162,7 +181,7 @@ namespace Umbraco.Core.Services if (dataType.Level != 1) { //get url encoded folder names - var folders = dataTypeService.GetContainers(dataType) + var folders = _dataTypeService.GetContainers(dataType) .OrderBy(x => x.Level) .Select(x => HttpUtility.UrlEncode(x.Name)); @@ -175,7 +194,45 @@ namespace Umbraco.Core.Services return xml; } - public XElement Serialize(IDictionaryItem dictionaryItem) + /// + /// Exports a list of items to xml as an + /// + /// List of dictionary items to export + /// Optional boolean indicating whether or not to include children + /// containing the xml representation of the IDictionaryItem objects + public XElement Serialize(IEnumerable dictionaryItem, bool includeChildren = true) + { + var xml = new XElement("DictionaryItems"); + foreach (var item in dictionaryItem) + { + xml.Add(Serialize(item, includeChildren)); + } + return xml; + } + + /// + /// Exports a single item to xml as an + /// + /// Dictionary Item to export + /// Optional boolean indicating whether or not to include children + /// containing the xml representation of the IDictionaryItem object + public XElement Serialize(IDictionaryItem dictionaryItem, bool includeChildren) + { + var xml = Serialize(dictionaryItem); + + if (includeChildren) + { + var children = _localizationService.GetDictionaryItemChildren(dictionaryItem.Key); + foreach (var child in children) + { + xml.Add(Serialize(child, true)); + } + } + + return xml; + } + + private XElement Serialize(IDictionaryItem dictionaryItem) { var xml = new XElement("DictionaryItem", new XAttribute("Key", dictionaryItem.ItemKey)); foreach (var translation in dictionaryItem.Translations) @@ -210,6 +267,21 @@ namespace Umbraco.Core.Services return xml; } + /// + /// Exports a list of items to xml as an + /// + /// List of Languages to export + /// containing the xml representation of the ILanguage objects + public XElement Serialize(IEnumerable languages) + { + var xml = new XElement("Languages"); + foreach (var language in languages) + { + xml.Add(Serialize(language)); + } + return xml; + } + public XElement Serialize(ILanguage language) { var xml = new XElement("Language", @@ -240,7 +312,22 @@ namespace Umbraco.Core.Services return xml; } - public XElement Serialize(IDataTypeService dataTypeService, IMediaType mediaType) + /// + /// Exports a list of items to xml as an + /// + /// + /// + public XElement Serialize(IEnumerable templates) + { + var xml = new XElement("Templates"); + foreach (var item in templates) + { + xml.Add(Serialize(item)); + } + return xml; + } + + public XElement Serialize(IMediaType mediaType) { var info = new XElement("Info", new XElement("Name", mediaType.Name), @@ -263,7 +350,7 @@ namespace Umbraco.Core.Services var genericProperties = new XElement("GenericProperties"); // actually, all of them foreach (var propertyType in mediaType.PropertyTypes) { - var definition = dataTypeService.GetDataType(propertyType.DataTypeId); + var definition = _dataTypeService.GetDataType(propertyType.DataTypeId); var propertyGroup = propertyType.PropertyGroupId == null // true generic property ? null @@ -301,6 +388,21 @@ namespace Umbraco.Core.Services return xml; } + /// + /// Exports a list of items to xml as an + /// + /// Macros to export + /// containing the xml representation of the IMacro objects + public XElement Serialize(IEnumerable macros) + { + var xml = new XElement("Macros"); + foreach (var item in macros) + { + xml.Add(Serialize(item)); + } + return xml; + } + public XElement Serialize(IMacro macro) { var xml = new XElement("macro"); @@ -328,7 +430,7 @@ namespace Umbraco.Core.Services return xml; } - public XElement Serialize(IDataTypeService dataTypeService, IContentTypeService contentTypeService, IContentType contentType) + public XElement Serialize(IContentType contentType) { var info = new XElement("Info", new XElement("Name", contentType.Name), @@ -372,7 +474,7 @@ namespace Umbraco.Core.Services var genericProperties = new XElement("GenericProperties"); // actually, all of them foreach (var propertyType in contentType.PropertyTypes) { - var definition = dataTypeService.GetDataType(propertyType.DataTypeId); + var definition = _dataTypeService.GetDataType(propertyType.DataTypeId); var propertyGroup = propertyType.PropertyGroupId == null // true generic property ? null @@ -413,7 +515,7 @@ namespace Umbraco.Core.Services if (contentType.Level != 1 && masterContentType == null) { //get url encoded folder names - var folders = contentTypeService.GetContainers(contentType) + var folders = _contentTypeService.GetContainers(contentType) .OrderBy(x => x.Level) .Select(x => HttpUtility.UrlEncode(x.Name)); @@ -427,7 +529,7 @@ namespace Umbraco.Core.Services } // exports an IContentBase (IContent, IMedia or IMember) as an XElement. - private static XElement SerializeContentBase(IDataTypeService dataTypeService, ILocalizationService localizationService, IContentBase contentBase, string urlValue, string nodeName, bool published) + private XElement SerializeContentBase(IContentBase contentBase, string urlValue, string nodeName, bool published) { var xml = new XElement(nodeName, new XAttribute("id", contentBase.Id), @@ -444,13 +546,13 @@ namespace Umbraco.Core.Services new XAttribute("isDoc", "")); foreach (var property in contentBase.Properties) - xml.Add(SerializeProperty(dataTypeService, localizationService, property, published)); + xml.Add(SerializeProperty(property, published)); return xml; } // exports a property as XElements. - private static IEnumerable SerializeProperty(IDataTypeService dataTypeService, ILocalizationService localizationService, Property property, bool published) + private IEnumerable SerializeProperty(Property property, bool published) { var propertyType = property.PropertyType; @@ -458,16 +560,16 @@ namespace Umbraco.Core.Services var propertyEditor = Current.PropertyEditors[propertyType.PropertyEditorAlias]; return propertyEditor == null ? Array.Empty() - : propertyEditor.GetValueEditor().ConvertDbToXml(property, dataTypeService, localizationService, published); + : propertyEditor.GetValueEditor().ConvertDbToXml(property, _dataTypeService, _localizationService, published); } // exports an IContent item descendants. - private static void SerializeChildren(IContentService contentService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IEnumerable children, XElement xml, bool published) + private void SerializeChildren(IEnumerable children, XElement xml, bool published) { foreach (var child in children) { // add the child xml - var childXml = Serialize(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, child, published); + var childXml = Serialize(child, published); xml.Add(childXml); const int pageSize = 500; @@ -475,20 +577,20 @@ namespace Umbraco.Core.Services var total = long.MaxValue; while(page * pageSize < total) { - var grandChildren = contentService.GetPagedChildren(child.Id, page++, pageSize, out total); + var grandChildren = _contentService.GetPagedChildren(child.Id, page++, pageSize, out total); // recurse - SerializeChildren(contentService, dataTypeService, userService, localizationService, urlSegmentProviders, grandChildren, childXml, published); + SerializeChildren(grandChildren, childXml, published); } } } // exports an IMedia item descendants. - private static void SerializeChildren(IMediaService mediaService, IDataTypeService dataTypeService, IUserService userService, ILocalizationService localizationService, IEnumerable urlSegmentProviders, IEnumerable children, XElement xml) + private void SerializeChildren(IEnumerable children, XElement xml) { foreach (var child in children) { // add the child xml - var childXml = Serialize(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, child); + var childXml = Serialize(child); xml.Add(childXml); const int pageSize = 500; @@ -496,9 +598,9 @@ namespace Umbraco.Core.Services var total = long.MaxValue; while (page * pageSize < total) { - var grandChildren = mediaService.GetPagedChildren(child.Id, page++, pageSize, out total); + var grandChildren = _mediaService.GetPagedChildren(child.Id, page++, pageSize, out total); // recurse - SerializeChildren(mediaService, dataTypeService, userService, localizationService, urlSegmentProviders, grandChildren, childXml); + SerializeChildren(grandChildren, childXml); } } } diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 106d2b9f12..203a2cb2e8 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -8,8 +7,6 @@ using System.Text.RegularExpressions; using System.Web; using System.Xml.Linq; using Umbraco.Core.Collections; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; @@ -18,8 +15,6 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; -using Umbraco.Core.Packaging.Models; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.PropertyEditors; @@ -35,56 +30,53 @@ namespace Umbraco.Core.Services.Implement /// public class PackagingService : IPackagingService { + //fixme: inject when ready to use this + private IPackageInstallation _packageInstallation; + private readonly ILogger _logger; private readonly IContentService _contentService; private readonly IContentTypeService _contentTypeService; - private readonly IMediaService _mediaService; private readonly IMacroService _macroService; private readonly IDataTypeService _dataTypeService; private readonly IFileService _fileService; private readonly ILocalizationService _localizationService; private readonly IEntityService _entityService; private readonly IScopeProvider _scopeProvider; - private readonly IEnumerable _urlSegmentProviders; private Dictionary _importedContentTypes; - private IPackageInstallation _packageInstallation; - private readonly IUserService _userService; private readonly IAuditRepository _auditRepository; private readonly IContentTypeRepository _contentTypeRepository; private readonly PropertyEditorCollection _propertyEditors; + private readonly IPackageCreation _packageCreation; private static HttpClient _httpClient; public PackagingService( ILogger logger, IContentService contentService, IContentTypeService contentTypeService, - IMediaService mediaService, IMacroService macroService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IEntityService entityService, - IUserService userService, IScopeProvider scopeProvider, - UrlSegmentProviderCollection urlSegmentProviders, - IAuditRepository auditRepository, IContentTypeRepository contentTypeRepository, - PropertyEditorCollection propertyEditors) + IAuditRepository auditRepository, + IContentTypeRepository contentTypeRepository, + PropertyEditorCollection propertyEditors, + IPackageCreation packageCreation) { _logger = logger; _contentService = contentService; _contentTypeService = contentTypeService; - _mediaService = mediaService; _macroService = macroService; _dataTypeService = dataTypeService; _fileService = fileService; _localizationService = localizationService; _entityService = entityService; _scopeProvider = scopeProvider; - _urlSegmentProviders = urlSegmentProviders; _auditRepository = auditRepository; _contentTypeRepository = contentTypeRepository; _propertyEditors = propertyEditors; - _userService = userService; + _packageCreation = packageCreation; _importedContentTypes = new Dictionary(); } @@ -92,31 +84,7 @@ namespace Umbraco.Core.Services.Implement #region Content - /// - /// Exports an item to xml as an - /// - /// Content to export - /// Optional parameter indicating whether to include descendents - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the Content object - public XElement Export(IContent content, bool deep = false, bool raiseEvents = true) - { - var nodeName = content.ContentType.Alias.ToSafeAliasWithForcingCheck(); - - if (raiseEvents) - { - if (ExportingContent.IsRaisedEventCancelled(new ExportEventArgs(content, nodeName), this)) - return new XElement(nodeName); - } - - const bool published = false; // fixme - what shall we export? - var xml = EntityXmlSerializer.Serialize(_contentService, _dataTypeService, _userService, _localizationService, _urlSegmentProviders, content, published, deep); - - if (raiseEvents) - ExportedContent.RaiseEvent(new ExportEventArgs(content, xml, false), this); - - return xml; - } + @@ -308,28 +276,7 @@ namespace Umbraco.Core.Services.Implement #region ContentTypes - /// - /// Exports an to xml as an - /// - /// ContentType to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ContentType item. - public XElement Export(IContentType contentType, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ExportingContentType.IsRaisedEventCancelled(new ExportEventArgs(contentType, "DocumentType"), this)) - return new XElement("DocumentType"); - } - - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(_dataTypeService, _contentTypeService, contentType); - - if (raiseEvents) - ExportedContentType.RaiseEvent(new ExportEventArgs(contentType, xml, false), this); - - return xml; - } + /// /// Imports and saves package xml as @@ -804,44 +751,9 @@ namespace Umbraco.Core.Services.Implement #region DataTypes - /// - /// Exports a list of Data Types - /// - /// List of data types to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDataTypeDefinition objects - public XElement Export(IEnumerable dataTypeDefinitions, bool raiseEvents = true) - { - var container = new XElement("DataTypes"); - foreach (var dataTypeDefinition in dataTypeDefinitions) - { - container.Add(Export(dataTypeDefinition, raiseEvents)); - } - return container; - } + - /// - /// Exports a single Data Type - /// - /// Data type to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDataTypeDefinition object - public XElement Export(IDataType dataType, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ExportingDataType.IsRaisedEventCancelled(new ExportEventArgs(dataType, "DataType"), this)) - return new XElement("DataType"); - } - - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(_dataTypeService, dataType); - - if (raiseEvents) - ExportedDataType.RaiseEvent(new ExportEventArgs(dataType, xml, false), this); - - return xml; - } + /// /// Imports and saves package xml as @@ -993,55 +905,9 @@ namespace Umbraco.Core.Services.Implement #region Dictionary Items - /// - /// Exports a list of items to xml as an - /// - /// List of dictionary items to export - /// Optional boolean indicating whether or not to include children - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDictionaryItem objects - public XElement Export(IEnumerable dictionaryItem, bool includeChildren = true, bool raiseEvents = true) - { - var xml = new XElement("DictionaryItems"); - foreach (var item in dictionaryItem) - { - xml.Add(Export(item, includeChildren, raiseEvents)); - } - return xml; - } + - /// - /// Exports a single item to xml as an - /// - /// Dictionary Item to export - /// Optional boolean indicating whether or not to include children - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IDictionaryItem object - public XElement Export(IDictionaryItem dictionaryItem, bool includeChildren, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ExportingDictionaryItem.IsRaisedEventCancelled(new ExportEventArgs(dictionaryItem, "DictionaryItem"), this)) - return new XElement("DictionaryItem"); - } - - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(dictionaryItem); - - if (includeChildren) - { - var children = _localizationService.GetDictionaryItemChildren(dictionaryItem.Key); - foreach (var child in children) - { - xml.Add(Export(child, true)); - } - } - - if (raiseEvents) - ExportedDictionaryItem.RaiseEvent(new ExportEventArgs(dictionaryItem, xml, false), this); - - return xml; - } + /// /// Imports and saves the 'DictionaryItems' part of the package xml as a list of @@ -1138,44 +1004,9 @@ namespace Umbraco.Core.Services.Implement #region Languages - /// - /// Exports a list of items to xml as an - /// - /// List of Languages to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ILanguage objects - public XElement Export(IEnumerable languages, bool raiseEvents = true) - { - var xml = new XElement("Languages"); - foreach (var language in languages) - { - xml.Add(Export(language, raiseEvents)); - } - return xml; - } + - /// - /// Exports a single item to xml as an - /// - /// Language to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ILanguage object - public XElement Export(ILanguage language, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ExportingLanguage.IsRaisedEventCancelled(new ExportEventArgs(language, "Language"), this)) - return new XElement("Language"); - } - - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(language); - - if (raiseEvents) - ExportedLanguage.RaiseEvent(new ExportEventArgs(language, xml, false), this); - - return xml; - } + /// /// Imports and saves the 'Languages' part of a package xml as a list of @@ -1326,109 +1157,10 @@ namespace Umbraco.Core.Services.Implement return macro; } - /// - /// Exports a list of items to xml as an - /// - /// Macros to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IMacro objects - public XElement Export(IEnumerable macros, bool raiseEvents = true) - { - var xml = new XElement("Macros"); - foreach (var item in macros) - { - xml.Add(Export(item, raiseEvents)); - } - return xml; - } + - /// - /// Exports a single item to xml as an - /// - /// Macro to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the IMacro object - public XElement Export(IMacro macro, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ExportingMacro.IsRaisedEventCancelled(new ExportEventArgs(macro, "macro"), this)) - return new XElement("macro"); - } + - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(macro); - - if (raiseEvents) - ExportedMacro.RaiseEvent(new ExportEventArgs(macro, xml, false), this); - - return xml; - } - - #endregion - - #region Members - - /// - /// Exports an item to xml as an - /// - /// Member to export - /// containing the xml representation of the Member object - public XElement Export(IMember member) - { - return EntityXmlSerializer.Serialize(_dataTypeService, _localizationService, member); - } - - #endregion - - #region Media - - /// - /// Exports an item to xml as an - /// - /// Media to export - /// Optional parameter indicating whether to include descendents - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the Media object - public XElement Export(IMedia media, bool deep = false, bool raiseEvents = true) - { - var nodeName = media.ContentType.Alias.ToSafeAliasWithForcingCheck(); - - if (raiseEvents) - { - if (ExportingMedia.IsRaisedEventCancelled(new ExportEventArgs(media, nodeName), this)) - return new XElement(nodeName); - } - - var xml = EntityXmlSerializer.Serialize(_mediaService, _dataTypeService, _userService, _localizationService, _urlSegmentProviders, media, deep); - - if (raiseEvents) - ExportedMedia.RaiseEvent(new ExportEventArgs(media, xml, false), this); - - return xml; - } - - - #endregion - - #region MediaTypes - - /// - /// Exports an to xml as an - /// - /// MediaType to export - /// containing the xml representation of the MediaType item. - internal XElement Export(IMediaType mediaType) - { - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(_dataTypeService, mediaType); - - return xml; - } - - #endregion - - #region Package Manifest #endregion #region Package Files @@ -1579,6 +1311,26 @@ namespace Umbraco.Core.Services.Implement } + private bool IsMasterPageSyntax(string code) + { + return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || + code.InvariantContains(" ImportStylesheets(XElement element, int userId = 0, bool raiseEvents = true) { @@ -1601,69 +1353,12 @@ namespace Umbraco.Core.Services.Implement } - - private bool IsMasterPageSyntax(string code) - { - return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || - code.InvariantContains(" - /// Exports a list of items to xml as an - /// - /// List of Templates to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ITemplate objects - public XElement Export(IEnumerable templates, bool raiseEvents = true) - { - var xml = new XElement("Templates"); - foreach (var item in templates) - { - xml.Add(Export(item, raiseEvents)); - } - return xml; - } - - /// - /// Exports a single item to xml as an - /// - /// Template to export - /// Optional parameter indicating whether or not to raise events - /// containing the xml representation of the ITemplate object - public XElement Export(ITemplate template, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ExportingTemplate.IsRaisedEventCancelled(new ExportEventArgs(template, "Template"), this)) - return new XElement("Template"); - } - - var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(template); - - if (raiseEvents) - ExportedTemplate.RaiseEvent(new ExportEventArgs(template, xml, false), this); - - return xml; - } - - #endregion - - #region Stylesheets #endregion #region Installation + //fixme: None of these methods are actually used! They have unit tests for them though, but we don't actively use this yet but we should! + internal IPackageInstallation PackageInstallation { private get { return _packageInstallation ?? new PackageInstallation(this, _macroService, _fileService, new PackageExtraction()); } @@ -1706,6 +1401,9 @@ namespace Umbraco.Core.Services.Implement #endregion #region Package Building + + public void SavePackageDefinition(PackageDefinition definition) => _packageCreation.SavePackageDefinition(definition); + #endregion /// @@ -1737,24 +1435,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedContent; - - public static event TypedEventHandler> ExportingContent; - - /// - /// Occurs after Content is Exported to Xml - /// - public static event TypedEventHandler> ExportedContent; - - /// - /// Occurs before Exporting Media - /// - public static event TypedEventHandler> ExportingMedia; - - /// - /// Occurs after Media is Exported to Xml - /// - public static event TypedEventHandler> ExportedMedia; - /// /// Occurs before Importing ContentType /// @@ -1765,16 +1445,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedContentType; - /// - /// Occurs before Exporting ContentType - /// - public static event TypedEventHandler> ExportingContentType; - - /// - /// Occurs after ContentType is Exported to Xml - /// - public static event TypedEventHandler> ExportedContentType; - /// /// Occurs before Importing DataType /// @@ -1785,16 +1455,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedDataType; - /// - /// Occurs before Exporting DataType - /// - public static event TypedEventHandler> ExportingDataType; - - /// - /// Occurs after DataType is Exported to Xml - /// - public static event TypedEventHandler> ExportedDataType; - /// /// Occurs before Importing DictionaryItem /// @@ -1805,16 +1465,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedDictionaryItem; - /// - /// Occurs before Exporting DictionaryItem - /// - public static event TypedEventHandler> ExportingDictionaryItem; - - /// - /// Occurs after DictionaryItem is Exported to Xml - /// - public static event TypedEventHandler> ExportedDictionaryItem; - /// /// Occurs before Importing Macro /// @@ -1825,16 +1475,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedMacro; - /// - /// Occurs before Exporting Macro - /// - public static event TypedEventHandler> ExportingMacro; - - /// - /// Occurs after Macro is Exported to Xml - /// - public static event TypedEventHandler> ExportedMacro; - /// /// Occurs before Importing Language /// @@ -1845,16 +1485,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedLanguage; - /// - /// Occurs before Exporting Language - /// - public static event TypedEventHandler> ExportingLanguage; - - /// - /// Occurs after Language is Exported to Xml - /// - public static event TypedEventHandler> ExportedLanguage; - /// /// Occurs before Importing Template /// @@ -1870,16 +1500,6 @@ namespace Umbraco.Core.Services.Implement /// public static event TypedEventHandler> ImportedTemplate; - /// - /// Occurs before Exporting Template - /// - public static event TypedEventHandler> ExportingTemplate; - - /// - /// Occurs after Template is Exported to Xml - /// - public static event TypedEventHandler> ExportedTemplate; - /// /// Occurs before Importing umbraco package /// @@ -1896,5 +1516,7 @@ namespace Umbraco.Core.Services.Implement public static event TypedEventHandler> UninstalledPackage; #endregion + + } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index a01bbf1746..58ba136cc4 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -429,6 +429,9 @@ + + + @@ -440,6 +443,10 @@ + + + + @@ -554,7 +561,6 @@ - @@ -883,7 +889,7 @@ - + @@ -1351,6 +1357,7 @@ + @@ -1370,7 +1377,7 @@ - + @@ -1525,6 +1532,7 @@ + \ No newline at end of file diff --git a/src/Umbraco.Core/_Legacy/PackageActions/PackageActionCollection.cs b/src/Umbraco.Core/_Legacy/PackageActions/PackageActionCollection.cs index 46ea3c1e39..a38c8cea56 100644 --- a/src/Umbraco.Core/_Legacy/PackageActions/PackageActionCollection.cs +++ b/src/Umbraco.Core/_Legacy/PackageActions/PackageActionCollection.cs @@ -3,7 +3,7 @@ using Umbraco.Core.Composing; namespace Umbraco.Core._Legacy.PackageActions { - internal class PackageActionCollection : BuilderCollectionBase + public sealed class PackageActionCollection : BuilderCollectionBase { public PackageActionCollection(IEnumerable items) : base(items) diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 28e753cadc..12ea87087d 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Tests.Testing.Objects.Accessors; @@ -66,7 +67,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var domainCache = new DomainCache(ServiceContext.DomainService, DefaultCultureAccessor); var publishedShapshot = new Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedSnapshot( new PublishedContentCache(xmlStore, domainCache, cacheProvider, globalSettings, new SiteDomainHelper(), ContentTypesCache, null, null), - new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, cacheProvider, ContentTypesCache), + new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, cacheProvider, ContentTypesCache, Factory.GetInstance()), new PublishedMemberCache(null, cacheProvider, Current.Services.MemberService, ContentTypesCache), domainCache); var publishedSnapshotService = new Mock(); diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs index 5237b92ab8..acf76ca8d7 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs @@ -15,6 +15,7 @@ using Umbraco.Tests.Testing; using Current = Umbraco.Web.Composing.Current; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Services; using Umbraco.Tests.PublishedContent; namespace Umbraco.Tests.Cache.PublishedCache @@ -74,7 +75,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var mChild2 = MakeNewMedia("Child2", mType, user, mRoot2.Id); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); var roots = cache.GetAtRoot(); Assert.AreEqual(2, roots.Count()); Assert.IsTrue(roots.Select(x => x.Id).ContainsAll(new[] {mRoot1.Id, mRoot2.Id})); @@ -92,7 +93,7 @@ namespace Umbraco.Tests.Cache.PublishedCache //var publishedMedia = PublishedMediaTests.GetNode(mRoot.Id, GetUmbracoContext("/test", 1234)); var umbracoContext = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); var publishedMedia = cache.GetById(mRoot.Id); Assert.IsNotNull(publishedMedia); @@ -203,7 +204,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var result = new SearchResult("1234", 1, 1, () => fields.ToDictionary(x => x.Key, x => new List { x.Value })); - var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); + var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); var doc = store.CreateFromCacheValues(store.ConvertFromSearchResult(result)); DoAssert(doc, 1234, key, 0, 0, "/media/test.jpg", "Image", 23, "Shannon", "Shannon", 0, 0, "-1,1234", DateTime.Parse("2012-07-17T10:34:09"), DateTime.Parse("2012-07-16T10:34:09"), 2); @@ -219,7 +220,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var xmlDoc = GetMediaXml(); ((XmlElement)xmlDoc.DocumentElement.FirstChild).SetAttribute("key", key.ToString()); var navigator = xmlDoc.SelectSingleNode("/root/Image").CreateNavigator(); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); var doc = cache.CreateFromCacheValues(cache.ConvertFromXPathNavigator(navigator, true)); DoAssert(doc, 2000, key, 0, 2, "image1", "Image", 23, "Shannon", "Shannon", 33, 33, "-1,2000", DateTime.Parse("2012-06-12T14:13:17"), DateTime.Parse("2012-07-20T18:50:43"), 1); diff --git a/src/Umbraco.Tests/Models/ContentXmlTest.cs b/src/Umbraco.Tests/Models/ContentXmlTest.cs index ab318ec1cb..3779993d22 100644 --- a/src/Umbraco.Tests/Models/ContentXmlTest.cs +++ b/src/Umbraco.Tests/Models/ContentXmlTest.cs @@ -2,7 +2,9 @@ using System.Xml.Linq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Composing; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; @@ -29,7 +31,7 @@ namespace Umbraco.Tests.Models var urlName = content.GetUrlSegment(new[]{new DefaultUrlSegmentProvider() }); // Act - XElement element = content.ToXml(); + XElement element = content.ToXml(Factory.GetInstance()); // Assert Assert.That(element, Is.Not.Null); diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 1a56fac4eb..d0d00c64a6 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -3,6 +3,7 @@ using System.Xml.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -50,7 +51,7 @@ namespace Umbraco.Tests.Models var urlName = media.GetUrlSegment(new[] { new DefaultUrlSegmentProvider() }); // Act - XElement element = media.ToXml(); + XElement element = media.ToXml(Factory.GetInstance()); // Assert Assert.That(element, Is.Not.Null); diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 3ba0ef64ce..ef37a822c1 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -152,7 +152,8 @@ namespace Umbraco.Tests.PublishedContent new TestDefaultCultureAccessor(), dataSource, globalSettings, - new SiteDomainHelper()); + new SiteDomainHelper(), + Mock.Of()); // get a snapshot, get a published content var snapshot = snapshotService.CreatePublishedSnapshot(previewToken: null); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 88b211d0ee..4f55b4fd71 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -22,6 +22,7 @@ using Umbraco.Tests.Testing; using Umbraco.Core.Composing; using Umbraco.Core.Models.Membership; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; namespace Umbraco.Tests.PublishedContent { @@ -66,7 +67,9 @@ namespace Umbraco.Tests.PublishedContent /// internal IPublishedContent GetNode(int id, UmbracoContext umbracoContext) { - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), + ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, + Factory.GetInstance()); var doc = cache.GetById(id); Assert.IsNotNull(doc); return doc; @@ -123,7 +126,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -153,7 +156,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //ensure it is found var publishedMedia = cache.GetById(3113); @@ -200,7 +203,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -228,7 +231,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -256,7 +259,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -285,7 +288,7 @@ namespace Umbraco.Tests.PublishedContent var ctx = GetUmbracoContext("/test"); var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(3113); @@ -311,7 +314,7 @@ namespace Umbraco.Tests.PublishedContent var ctx = GetUmbracoContext("/test"); var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(3113); @@ -479,7 +482,7 @@ namespace Umbraco.Tests.PublishedContent "); var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); var nav = node.CreateNavigator(); @@ -499,7 +502,7 @@ namespace Umbraco.Tests.PublishedContent var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); var nav = errorXml.CreateNavigator(); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); Assert.IsNull(converted); diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index b273ee9526..e8f3463ca7 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -95,7 +95,8 @@ namespace Umbraco.Tests.Scoping documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, new DatabaseDataSource(), - Factory.GetInstance(), new SiteDomainHelper()); + Factory.GetInstance(), new SiteDomainHelper(), + Factory.GetInstance()); } protected UmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable urlProviders = null) diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index 94d2126bd2..d0c0b93b48 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -67,7 +67,8 @@ namespace Umbraco.Tests.Services documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, new DatabaseDataSource(), - Factory.GetInstance(), new SiteDomainHelper()); + Factory.GetInstance(), new SiteDomainHelper(), + Factory.GetInstance()); } public class LocalServerMessenger : ServerMessengerBase diff --git a/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs b/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs new file mode 100644 index 0000000000..28c69344b7 --- /dev/null +++ b/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; +using Umbraco.Core.Composing; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Tests.Services.Importing; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Services +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class EntityXmlSerializerTests : TestWithSomeContentBase + { + private IEntityXmlSerializer Serializer => Factory.GetInstance(); + + [Test] + public void Can_Export_Macro() + { + // Arrange + var macro = new Macro("test1", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView); + ServiceContext.MacroService.Save(macro); + + // Act + var element = Serializer.Serialize(macro); + + // Assert + Assert.That(element, Is.Not.Null); + Assert.That(element.Element("name").Value, Is.EqualTo("Test")); + Assert.That(element.Element("alias").Value, Is.EqualTo("test1")); + Debug.Print(element.ToString()); + } + + [Test] + public void Can_Export_DictionaryItems() + { + // Arrange + CreateDictionaryData(); + var dictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Parent"); + + var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); + var dictionaryItemsElement = newPackageXml.Elements("DictionaryItems").First(); + + // Act + var xml = Serializer.Serialize(new[] { dictionaryItem }); + + // Assert + Assert.That(xml.ToString(), Is.EqualTo(dictionaryItemsElement.ToString())); + } + + [Test] + public void Can_Export_Languages() + { + // Arrange + var languageNbNo = new Language("nb-NO") { CultureName = "Norwegian" }; + ServiceContext.LocalizationService.Save(languageNbNo); + + var languageEnGb = new Language("en-GB") { CultureName = "English (United Kingdom)" }; + ServiceContext.LocalizationService.Save(languageEnGb); + + var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); + var languageItemsElement = newPackageXml.Elements("Languages").First(); + + // Act + var xml = Serializer.Serialize(new[] { languageNbNo, languageEnGb }); + + // Assert + Assert.That(xml.ToString(), Is.EqualTo(languageItemsElement.ToString())); + } + + private void CreateDictionaryData() + { + var languageNbNo = new Language("nb-NO") { CultureName = "nb-NO" }; + ServiceContext.LocalizationService.Save(languageNbNo); + + var languageEnGb = new Language("en-GB") { CultureName = "en-GB" }; + ServiceContext.LocalizationService.Save(languageEnGb); + + var parentItem = new DictionaryItem("Parent"); + var parentTranslations = new List + { + new DictionaryTranslation(languageNbNo, "ForelderVerdi"), + new DictionaryTranslation(languageEnGb, "ParentValue") + }; + parentItem.Translations = parentTranslations; + ServiceContext.LocalizationService.Save(parentItem); + + var childItem = new DictionaryItem(parentItem.Key, "Child"); + var childTranslations = new List + { + new DictionaryTranslation(languageNbNo, "BarnVerdi"), + new DictionaryTranslation(languageEnGb, "ChildValue") + }; + childItem.Translations = childTranslations; + ServiceContext.LocalizationService.Save(childItem); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs index 8e67aa4e1f..84eb75a4f7 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Composing.Composers; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Services.Importing @@ -416,11 +417,12 @@ namespace Umbraco.Tests.Services.Importing string strXml = ImportResources.SingleDocType; var docTypeElement = XElement.Parse(strXml); var packagingService = ServiceContext.PackagingService; + var serializer = Factory.GetInstance(); // Act var contentTypes = packagingService.ImportContentTypes(docTypeElement); var contentType = contentTypes.FirstOrDefault(); - var element = packagingService.Export(contentType); + var element = serializer.Serialize(contentType); // Assert Assert.That(element, Is.Not.Null); diff --git a/src/Umbraco.Tests/Services/PackagingServiceTests.cs b/src/Umbraco.Tests/Services/PackagingServiceTests.cs index 87225c1288..a87e7907b5 100644 --- a/src/Umbraco.Tests/Services/PackagingServiceTests.cs +++ b/src/Umbraco.Tests/Services/PackagingServiceTests.cs @@ -1,16 +1,9 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.Linq; -using System.Xml.Linq; using NUnit.Framework; using Umbraco.Core.IO; -using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.Services.Importing; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -20,59 +13,7 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class PackagingServiceTests : TestWithSomeContentBase { - [Test] - public void PackagingService_Can_Export_Macro() - { - // Arrange - var macro = new Macro("test1", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView); - ServiceContext.MacroService.Save(macro); - - // Act - var element = ServiceContext.PackagingService.Export(macro); - - // Assert - Assert.That(element, Is.Not.Null); - Assert.That(element.Element("name").Value, Is.EqualTo("Test")); - Assert.That(element.Element("alias").Value, Is.EqualTo("test1")); - Debug.Print(element.ToString()); - } - - [Test] - public void PackagingService_Can_Export_DictionaryItems() - { - // Arrange - CreateDictionaryData(); - var dictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Parent"); - - var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); - var dictionaryItemsElement = newPackageXml.Elements("DictionaryItems").First(); - - // Act - var xml = ServiceContext.PackagingService.Export(new []{dictionaryItem}); - - // Assert - Assert.That(xml.ToString(), Is.EqualTo(dictionaryItemsElement.ToString())); - } - - [Test] - public void PackagingService_Can_Export_Languages() - { - // Arrange - var languageNbNo = new Language("nb-NO") { CultureName = "Norwegian" }; - ServiceContext.LocalizationService.Save(languageNbNo); - - var languageEnGb = new Language("en-GB") { CultureName = "English (United Kingdom)" }; - ServiceContext.LocalizationService.Save(languageEnGb); - - var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); - var languageItemsElement = newPackageXml.Elements("Languages").First(); - - // Act - var xml = ServiceContext.PackagingService.Export(new[] { languageNbNo, languageEnGb }); - - // Assert - Assert.That(xml.ToString(), Is.EqualTo(languageItemsElement.ToString())); - } + private static string GetTestPackagePath(string packageName) { @@ -123,31 +64,6 @@ namespace Umbraco.Tests.Services Assert.IsNotNull(preInstallWarnings); } - private void CreateDictionaryData() - { - var languageNbNo = new Language("nb-NO") { CultureName = "nb-NO" }; - ServiceContext.LocalizationService.Save(languageNbNo); - - var languageEnGb = new Language("en-GB") { CultureName = "en-GB" }; - ServiceContext.LocalizationService.Save(languageEnGb); - - var parentItem = new DictionaryItem("Parent"); - var parentTranslations = new List - { - new DictionaryTranslation(languageNbNo, "ForelderVerdi"), - new DictionaryTranslation(languageEnGb, "ParentValue") - }; - parentItem.Translations = parentTranslations; - ServiceContext.LocalizationService.Save(parentItem); - - var childItem = new DictionaryItem(parentItem.Key, "Child"); - var childTranslations = new List - { - new DictionaryTranslation(languageNbNo, "BarnVerdi"), - new DictionaryTranslation(languageEnGb, "ChildValue") - }; - childItem.Translations = childTranslations; - ServiceContext.LocalizationService.Save(childItem); - } + } } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index cb36e6ca5f..120b0bcabb 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Repositories; @@ -167,7 +168,10 @@ namespace Umbraco.Tests.TestHelpers GetRepo(c))); var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); - var packagingService = GetLazyService(factory, c => new PackagingService(logger, contentService.Value, contentTypeService.Value, mediaService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, userService.Value, scopeProvider, urlSegmentProviders, GetRepo(c), GetRepo(c), new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())))); + var packagingService = GetLazyService(factory, c => new PackagingService( + logger, contentService.Value, contentTypeService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, scopeProvider, GetRepo(c), GetRepo(c), new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())), + new PackageCreation(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger))); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index a2a0c35c56..0729aa0b6e 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -268,6 +268,7 @@ namespace Umbraco.Tests.TestHelpers DefaultCultureAccessor, Logger, Factory.GetInstance(), new SiteDomainHelper(), + Factory.GetInstance(), ContentTypesCache, null, true, Options.PublishedRepositoryEvents); diff --git a/src/Umbraco.Tests/UI/LegacyDialogTests.cs b/src/Umbraco.Tests/UI/LegacyDialogTests.cs index be9b0d4d7e..5c8a621e10 100644 --- a/src/Umbraco.Tests/UI/LegacyDialogTests.cs +++ b/src/Umbraco.Tests/UI/LegacyDialogTests.cs @@ -24,7 +24,6 @@ namespace Umbraco.Tests.UI } [TestCase(typeof(macroTasks), Constants.Applications.Settings)] - [TestCase(typeof(CreatedPackageTasks), Constants.Applications.Packages)] public void Check_Assigned_Apps_For_Tasks(Type taskType, string app) { var task = (LegacyDialogTask)Activator.CreateInstance(taskType); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 661ccb6ab8..12b830407e 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -139,6 +139,7 @@ + diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index 0ad3bff109..192b0975d1 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -419,11 +419,13 @@ namespace Umbraco.Tests.Web.Mvc //var provider = new ScopeUnitOfWorkProvider(databaseFactory, new RepositoryFactory(Mock.Of())); var scopeProvider = TestObjects.GetScopeProvider(Mock.Of()); var factory = Mock.Of(); - _service = new PublishedSnapshotService(svcCtx, factory, scopeProvider, cache, Enumerable.Empty(), + _service = new PublishedSnapshotService(svcCtx, factory, scopeProvider, cache, null, null, null, null, null, new TestDefaultCultureAccessor(), - Current.Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), null, true, false); // no events + Current.Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), + Factory.GetInstance(), + null, true, false); // no events var http = GetHttpContextFactory(url, routeData).HttpContext; diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index ffe07393e6..3e7c14147b 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services; @@ -215,6 +216,8 @@ namespace Umbraco.Web.Composing internal static ManifestValueValidatorCollection ManifestValidators => CoreCurrent.ManifestValidators; + internal static PackageActionRunner PackageActionRunner => CoreCurrent.PackageActionRunner; + internal static PackageActionCollection PackageActions => CoreCurrent.PackageActions; internal static PropertyValueConverterCollection PropertyValueConverters => CoreCurrent.PropertyValueConverters; diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 397f6b3e9d..0d56b34617 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -11,10 +11,15 @@ using System.Web.Http; using System.Xml; using System.Xml.Linq; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Web.Composing; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; @@ -40,6 +45,13 @@ namespace Umbraco.Web.Editors [EnableOverrideAuthorization] public class ContentTypeController : ContentTypeControllerBase { + private readonly IEntityXmlSerializer _serializer; + + public ContentTypeController(IEntityXmlSerializer serializer, ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + { + _serializer = serializer; + } + public int GetCount() { return Services.ContentTypeService.Count(); @@ -444,11 +456,7 @@ namespace Umbraco.Web.Editors var contentType = Services.ContentTypeService.Get(id); if (contentType == null) throw new NullReferenceException("No content type found with id " + id); - var serializer = new EntityXmlSerializer(); - var xml = serializer.Serialize( - Services.DataTypeService, - Services.ContentTypeService, - contentType); + var xml = _serializer.Serialize(contentType); var response = new HttpResponseMessage { @@ -559,5 +567,7 @@ namespace Umbraco.Web.Editors return model; } + + } } diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs index 2572bed816..898208319a 100644 --- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs @@ -7,9 +7,13 @@ using System.Text; using System.Web.Http; using AutoMapper; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.Exceptions; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Models.ContentEditing; @@ -26,8 +30,16 @@ namespace Umbraco.Web.Editors public abstract class ContentTypeControllerBase : UmbracoAuthorizedJsonController where TContentType : class, IContentTypeComposition { + private readonly ICultureDictionaryFactory _cultureDictionaryFactory; private ICultureDictionary _cultureDictionary; + protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + { + _cultureDictionaryFactory = cultureDictionaryFactory; + } + + + /// /// Returns the available composite content types for a given content type /// @@ -536,6 +548,6 @@ namespace Umbraco.Web.Editors } private ICultureDictionary CultureDictionary - => _cultureDictionary ?? (_cultureDictionary = Current.CultureDictionaryFactory.CreateDictionary()); + => _cultureDictionary ?? (_cultureDictionary = _cultureDictionaryFactory.CreateDictionary()); } } diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index f8455fc01d..f2b8fd3dda 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -15,6 +15,11 @@ using System; using System.ComponentModel; using System.Web.Http.Controllers; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Dictionary; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; using Umbraco.Web.Composing; namespace Umbraco.Web.Editors @@ -32,6 +37,10 @@ namespace Umbraco.Web.Editors [MediaTypeControllerControllerConfiguration] public class MediaTypeController : ContentTypeControllerBase { + public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + { + } + /// /// Configures this controller with a custom action selector /// @@ -302,5 +311,7 @@ namespace Umbraco.Web.Editors getContentType: i => Services.MediaTypeService.Get(i), doCopy: (type, i) => Services.MediaTypeService.Copy(type, i)); } + + } } diff --git a/src/Umbraco.Web/Editors/MemberTypeController.cs b/src/Umbraco.Web/Editors/MemberTypeController.cs index 77ff974aaa..3abc0035d3 100644 --- a/src/Umbraco.Web/Editors/MemberTypeController.cs +++ b/src/Umbraco.Web/Editors/MemberTypeController.cs @@ -6,7 +6,13 @@ using System.Net.Http; using System.Web.Http; using System.Web.Security; using AutoMapper; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Dictionary; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; @@ -24,6 +30,10 @@ namespace Umbraco.Web.Editors [UmbracoTreeAuthorize(new string[] { Constants.Trees.MemberTypes, Constants.Trees.Members})] public class MemberTypeController : ContentTypeControllerBase { + public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + { + } + private readonly MembershipProvider _provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); [UmbracoTreeAuthorize(Constants.Trees.MemberTypes)] @@ -166,5 +176,7 @@ namespace Umbraco.Web.Editors return display; } + + } } diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 8b9e15f9d1..dfb8823a39 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -4,10 +4,12 @@ using System.Net; using System.Net.Http; using System.Net.Http.Formatting; using System.Web.Http; -using umbraco.cms.businesslogic.packager; +using Umbraco.Core.Models.Packaging; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; +using Umbraco.Web._Legacy.Packager.PackageInstance; namespace Umbraco.Web.Editors { @@ -21,14 +23,12 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageController : UmbracoAuthorizedJsonController { - [HttpGet] - public List GetCreatedPackages() + public List GetCreatedPackages() { return CreatedPackage.GetAllCreatedPackages().Select(x => x.Data).ToList(); } - [HttpGet] - public PackageInstance GetCreatedPackageById(int id) + public PackageDefinition GetCreatedPackageById(int id) { var package = CreatedPackage.GetById(id); if (package == null) @@ -37,44 +37,46 @@ namespace Umbraco.Web.Editors return package.Data; } - [HttpPost] - public PackageInstance PostCreatePackage(PackageInstance model) + public PackageDefinition PostUpdatePackage(PackageDefinition model) { + var package = CreatedPackage.GetById(model.Id); + if (package == null) + throw new HttpResponseException(HttpStatusCode.NotFound); + if (ModelState.IsValid == false) { //Throw/bubble up errors - throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); } - - var package = new CreatedPackage - { - Data = model - }; - //If ID is 0 & PackageGuid is null - its brand new - if(model.Id == 0 && model.PackageGuid == null) - { - //Brand new - package = CreatedPackage.MakeNew(model.Name); - - var packageId = package.Data.Id; - var packageGuid = package.Data.PackageGuid; - - //Need to reset the package ID - as the posted model the package ID is always 0 - //MakeNew will init create the XML & update the file and give us an ID to use - package.Data = model; - package.Data.Id = packageId; - package.Data.PackageGuid = packageGuid; - } - - //Save then publish - package.Save(); - package.Publish(); + package.Data = model; //We should have packagepath populated now return package.Data; } + public PackageDefinition PostCreatePackage(PackageDefinition model) + { + //creating requires an empty model/package id + if (model.Id != 0 || model.PackageGuid != null) + throw new HttpResponseException(HttpStatusCode.NotFound); + + if (ModelState.IsValid == false) + { + //Throw/bubble up errors + throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); + } + + //save it + Services.PackagingService.SavePackageDefinition(model); + + //then publish to get the file + //package.Publish(); + //TODO: We need a link to the downloadable zip file, in packagepath ? + + return model; + } + /// /// Deletes a created package /// diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 4898c54616..b58ed05bde 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -9,12 +9,15 @@ using System.Threading.Tasks; using System.Web.Http; using System.Xml; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Packaging.Models; +using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Packaging; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Web.Composing; @@ -40,6 +43,16 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageInstallController : UmbracoAuthorizedJsonController { + private readonly PackageActionRunner _packageActionRunner; + + public PackageInstallController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, + ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, + IProfilingLogger logger, IRuntimeState runtimeState, PackageActionRunner packageActionRunner) + : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + { + _packageActionRunner = packageActionRunner; + } + /// /// This checks if this package & version is alraedy installed /// @@ -128,14 +141,14 @@ namespace Umbraco.Web.Editors //Remove Document Types var contentTypes = new List(); var contentTypeService = Services.ContentTypeService; - foreach (var item in pack.Data.Documenttypes.ToArray()) + foreach (var item in pack.Data.DocumentTypes.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) continue; var contentType = contentTypeService.Get(nId); if (contentType == null) continue; contentTypes.Add(contentType); - pack.Data.Documenttypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); + pack.Data.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); } //Order the DocumentTypes before removing them @@ -195,8 +208,7 @@ namespace Umbraco.Web.Editors { try { - global::Umbraco.Web._Legacy.Packager.PackageInstance.PackageAction - .UndoPackageAction(pack.Data.Name, n.Attributes["alias"].Value, n); + _packageActionRunner.UndoPackageAction(pack.Data.Name, n.Attributes["alias"].Value, n); } catch (Exception ex) { diff --git a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs index 2b1fce884d..3baa5e85ff 100644 --- a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs +++ b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs @@ -1,4 +1,10 @@ -using Umbraco.Web.WebApi; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; +using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors @@ -13,5 +19,26 @@ namespace Umbraco.Web.Editors [ValidateAngularAntiForgeryToken] [AngularJsonOnlyConfiguration] public abstract class UmbracoAuthorizedJsonController : UmbracoAuthorizedApiController - { } + { + /// + /// Initializes a new instance of the with auto dependencies. + /// + protected UmbracoAuthorizedJsonController() + { + } + + /// + /// Initializes a new instance of the class with all its dependencies. + /// + /// + /// + /// + /// + /// + /// + /// + protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + { + } + } } diff --git a/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs b/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs index 74e82ecfe9..04d06845d9 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs @@ -87,5 +87,7 @@ namespace Umbraco.Web.Models.ContentEditing /// Property Group /// PropertyGroup + + //TODO: Dictionary? } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs index ce8b5835e2..f2392c9c3d 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs @@ -8,30 +8,29 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Security; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Core.Xml.XPath; using Umbraco.Web.PublishedCache.NuCache.Navigable; namespace Umbraco.Web.PublishedCache.NuCache { - class MemberCache : IPublishedMemberCache, INavigableData + internal class MemberCache : IPublishedMemberCache, INavigableData { private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; public readonly IVariationContextAccessor VariationContextAccessor; + private readonly IEntityXmlSerializer _entitySerializer; private readonly ICacheProvider _snapshotCache; private readonly IMemberService _memberService; - private readonly IDataTypeService _dataTypeService; - private readonly ILocalizationService _localizationService; private readonly PublishedContentTypeCache _contentTypeCache; private readonly bool _previewDefault; - public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, IDataTypeService dataTypeService, ILocalizationService localizationService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) + public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer) { _snapshotCache = snapshotCache; _publishedSnapshotAccessor = publishedSnapshotAccessor; VariationContextAccessor = variationContextAccessor; + _entitySerializer = entitySerializer; _memberService = memberService; - _dataTypeService = dataTypeService; - _localizationService = localizationService; _previewDefault = previewDefault; _contentTypeCache = contentTypeCache; } @@ -141,7 +140,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var result = _memberService.GetById(id); if (result == null) return null; - var s = EntityXmlSerializer.Serialize(_dataTypeService, _localizationService, result); + var s = _entitySerializer.Serialize(result); var n = s.GetXmlNode(); return n.CreateNavigator(); } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 3aa33f0e2f..4ebddee6dc 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -43,6 +43,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IMemberRepository _memberRepository; private readonly IGlobalSettings _globalSettings; private readonly ISiteDomainHelper _siteDomainHelper; + private readonly IEntityXmlSerializer _entitySerializer; private readonly IDefaultCultureAccessor _defaultCultureAccessor; // volatile because we read it with no lock @@ -85,7 +86,8 @@ namespace Umbraco.Web.PublishedCache.NuCache ILogger logger, IScopeProvider scopeProvider, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, - IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper) + IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, + IEntityXmlSerializer entitySerializer) : base(publishedSnapshotAccessor, variationContextAccessor) { //if (Interlocked.Increment(ref _singletonCheck) > 1) @@ -102,6 +104,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings; _siteDomainHelper = siteDomainHelper; + _entitySerializer = entitySerializer; // we always want to handle repository events, configured or not // assuming no repository event will trigger before the whole db is ready @@ -1011,7 +1014,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService), MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache), - MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, _serviceContext.DataTypeService, _serviceContext.LocalizationService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor), + MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _entitySerializer), DomainCache = domainCache, SnapshotCache = snapshotCache, ElementsCache = elementsCache diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index 229a981510..7ec935139e 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Xml; using Umbraco.Examine; using Umbraco.Core.Cache; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Web.Composing; namespace Umbraco.Web.PublishedCache.XmlPublishedCache @@ -37,14 +38,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // method GetExamineManagerSafe(). // private readonly ISearcher _searchProvider; - private readonly IIndex _indexProvider; private readonly XmlStore _xmlStore; private readonly PublishedContentTypeCache _contentTypeCache; + private readonly IEntityXmlSerializer _entitySerializer; // must be specified by the ctor private readonly ICacheProvider _cacheProvider; - public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache) + public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); @@ -53,6 +54,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _cacheProvider = cacheProvider; _xmlStore = xmlStore; _contentTypeCache = contentTypeCache; + _entitySerializer = entitySerializer; } /// @@ -61,18 +63,18 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// /// /// - /// /// /// - internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, BaseIndexProvider indexProvider, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache) + /// + internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _searchProvider = searchProvider ?? throw new ArgumentNullException(nameof(searchProvider)); - _indexProvider = indexProvider ?? throw new ArgumentNullException(nameof(indexProvider)); _cacheProvider = cacheProvider; _contentTypeCache = contentTypeCache; + _entitySerializer = entitySerializer; } static PublishedMediaCache() @@ -555,14 +557,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache return Enumerable.Empty(); } - var serialized = EntityXmlSerializer.Serialize( - Current.Services.MediaService, - Current.Services.DataTypeService, - Current.Services.UserService, - Current.Services.LocalizationService, - Current.UrlSegmentProviders, - media, - true); + var serialized = _entitySerializer.Serialize(media, true); var mediaIterator = serialized.CreateNavigator().Select("/"); diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs index 78585ba2e2..e286e9d95c 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs @@ -34,6 +34,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IGlobalSettings _globalSettings; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly ISiteDomainHelper _siteDomainHelper; + private readonly IEntityXmlSerializer _entitySerializer; #region Constructors @@ -42,20 +43,20 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IPublishedContentTypeFactory publishedContentTypeFactory, IScopeProvider scopeProvider, ICacheProvider requestCache, - IEnumerable segmentProviders, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, + IEntityXmlSerializer entitySerializer, MainDom mainDom, bool testing = false, bool enableRepositoryEvents = true) - : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, segmentProviders, + : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, publishedSnapshotAccessor, variationContextAccessor, documentRepository, mediaRepository, memberRepository, defaultCultureAccessor, - logger, globalSettings, siteDomainHelper, null, mainDom, testing, enableRepositoryEvents) + logger, globalSettings, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) { } // used in some tests @@ -69,27 +70,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, - PublishedContentTypeCache contentTypeCache, - MainDom mainDom, - bool testing, bool enableRepositoryEvents) - : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, Enumerable.Empty(), - publishedSnapshotAccessor, variationContextAccessor, - documentRepository, mediaRepository, memberRepository, - defaultCultureAccessor, - logger, globalSettings, siteDomainHelper, contentTypeCache, mainDom, testing, enableRepositoryEvents) - { } - - private PublishedSnapshotService(ServiceContext serviceContext, - IPublishedContentTypeFactory publishedContentTypeFactory, - IScopeProvider scopeProvider, - ICacheProvider requestCache, - IEnumerable segmentProviders, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, - IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, - IDefaultCultureAccessor defaultCultureAccessor, - ILogger logger, - IGlobalSettings globalSettings, - ISiteDomainHelper siteDomainHelper, + IEntityXmlSerializer entitySerializer, PublishedContentTypeCache contentTypeCache, MainDom mainDom, bool testing, bool enableRepositoryEvents) @@ -100,9 +81,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _contentTypeCache = contentTypeCache ?? new PublishedContentTypeCache(serviceContext.ContentTypeService, serviceContext.MediaTypeService, serviceContext.MemberTypeService, publishedContentTypeFactory, logger); - _xmlStore = new XmlStore(serviceContext, scopeProvider, _routesCache, - _contentTypeCache, segmentProviders, publishedSnapshotAccessor, mainDom, testing, enableRepositoryEvents, - documentRepository, mediaRepository, memberRepository, globalSettings); + _xmlStore = new XmlStore(serviceContext.ContentTypeService, serviceContext.ContentService, scopeProvider, _routesCache, + _contentTypeCache, publishedSnapshotAccessor, mainDom, testing, enableRepositoryEvents, + documentRepository, mediaRepository, memberRepository, globalSettings, entitySerializer); _domainService = serviceContext.DomainService; _memberService = serviceContext.MemberService; @@ -113,6 +94,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _requestCache = requestCache; _globalSettings = globalSettings; _siteDomainHelper = siteDomainHelper; + _entitySerializer = entitySerializer; } public override void Dispose() @@ -157,7 +139,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache return new PublishedSnapshot( new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _siteDomainHelper, _contentTypeCache, _routesCache, previewToken), - new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache), + new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer), new PublishedMemberCache(_xmlStore, _requestCache, _memberService, _contentTypeCache), domainCache); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs index fef5039579..614515e433 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs @@ -44,15 +44,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IMediaRepository _mediaRepository; private readonly IMemberRepository _memberRepository; private readonly IGlobalSettings _globalSettings; + private readonly IEntityXmlSerializer _entitySerializer; private XmlStoreFilePersister _persisterTask; private volatile bool _released; private bool _withRepositoryEvents; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly PublishedContentTypeCache _contentTypeCache; - private readonly IEnumerable _segmentProviders; private readonly RoutesCache _routesCache; - private readonly ServiceContext _serviceContext; // fixme WHY + private readonly IContentTypeService _contentTypeService; + private readonly IContentService _contentService; private readonly IScopeProvider _scopeProvider; #region Constructors @@ -61,22 +62,23 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// Initializes a new instance of the class. /// /// The default constructor will boot the cache, load data from file or database, /// wire events in order to manage changes, etc. - public XmlStore(ServiceContext serviceContext, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, - IEnumerable segmentProviders, IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings) - : this(serviceContext, scopeProvider, routesCache, contentTypeCache, segmentProviders, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, globalSettings) + public XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, + IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer) + : this(contentTypeService, contentService, scopeProvider, routesCache, contentTypeCache, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, globalSettings, entitySerializer) { } // internal for unit tests // no file nor db, no config check // fixme - er, we DO have a DB? - internal XmlStore(ServiceContext serviceContext, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, - IEnumerable segmentProviders, IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, - bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings) + internal XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, + IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, + bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer) { if (testing == false) EnsureConfigurationIsValid(); - _serviceContext = serviceContext; + _contentTypeService = contentTypeService; + _contentService = contentService; _scopeProvider = scopeProvider; _routesCache = routesCache; _contentTypeCache = contentTypeCache; @@ -85,8 +87,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _mediaRepository = mediaRepository; _memberRepository = memberRepository; _globalSettings = globalSettings; + _entitySerializer = entitySerializer; _xmlFileName = IOHelper.MapPath(SystemFiles.GetContentCacheXml(_globalSettings)); - _segmentProviders = segmentProviders; if (testing) { @@ -399,7 +401,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache try { var dtdInner = new StringBuilder(); - var contentTypes = _serviceContext.ContentTypeService.GetAll(); + var contentTypes = _contentTypeService.GetAll(); // though aliases should be safe and non null already? var aliases = contentTypes.Select(x => x.Alias.ToSafeAlias()).WhereNotNull(); foreach (var alias in aliases) @@ -556,7 +558,7 @@ AND (umbracoNode.id=@id)"; public XmlDocument GetPreviewXml(int contentId, bool includeSubs) { - var content = _serviceContext.ContentService.GetById(contentId); + var content = _contentService.GetById(contentId); var doc = (XmlDocument)Xml.Clone(); if (content == null) return doc; @@ -1065,7 +1067,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; continue; } - var content = _serviceContext.ContentService.GetById(payload.Id); + var content = _contentService.GetById(payload.Id); var current = safeXml.Xml.GetElementById(payload.Id.ToInvariantString()); if (content == null || content.Published == false || content.Trashed) @@ -1536,7 +1538,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; var entity = args.Entity; // serialize edit values for preview - var editXml = EntityXmlSerializer.Serialize(_serviceContext.ContentService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, entity, false).ToDataString(); + var editXml = _entitySerializer.Serialize(entity, false).ToDataString(); // change below to write only one row - not one per version var dto1 = new PreviewXmlDto @@ -1565,7 +1567,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; return; // serialize published values for content cache - var publishedXml = EntityXmlSerializer.Serialize(_serviceContext.ContentService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, entity, true).ToDataString(); + var publishedXml = _entitySerializer.Serialize(entity, true).ToDataString(); var dto2 = new ContentXmlDto { NodeId = entity.Id, Xml = publishedXml }; OnRepositoryRefreshed(db, dto2); @@ -1581,7 +1583,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; if (entity.Trashed) db.Execute("DELETE FROM cmsContentXml WHERE nodeId=@id", new { id = entity.Id }); - var xml = EntityXmlSerializer.Serialize(_serviceContext.MediaService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, entity).ToDataString(); + var xml = _entitySerializer.Serialize(entity).ToDataString(); var dto1 = new ContentXmlDto { NodeId = entity.Id, Xml = xml }; OnRepositoryRefreshed(db, dto1); @@ -1592,7 +1594,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; var db = args.Scope.Database; var entity = args.Entity; - var xml = EntityXmlSerializer.Serialize(_serviceContext.DataTypeService, _serviceContext.LocalizationService, entity).ToDataString(); + var xml = _entitySerializer.Serialize(entity).ToDataString(); var dto1 = new ContentXmlDto { NodeId = entity.Id, Xml = xml }; OnRepositoryRefreshed(db, dto1); @@ -1749,7 +1751,7 @@ WHERE cmsContentXml.nodeId IN ( var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); const bool published = true; // contentXml contains published content! var items = descendants.Select(c => new ContentXmlDto { NodeId = c.Id, Xml = - EntityXmlSerializer.Serialize(_serviceContext.ContentService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, c, published).ToDataString() }).ToArray(); + _entitySerializer.Serialize(c, published).ToDataString() }).ToArray(); db.BulkInsertRecords(items); processed += items.Length; } while (processed < total); @@ -1824,7 +1826,7 @@ WHERE cmsPreviewXml.nodeId IN ( var items = descendants.Select(c => new PreviewXmlDto { NodeId = c.Id, - Xml = EntityXmlSerializer.Serialize(_serviceContext.ContentService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, c, published).ToDataString() + Xml = _entitySerializer.Serialize(c, published).ToDataString() }).ToArray(); db.BulkInsertRecords(items); processed += items.Length; @@ -1894,7 +1896,7 @@ WHERE cmsContentXml.nodeId IN ( { var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml = - EntityXmlSerializer.Serialize(_serviceContext.MediaService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, m).ToDataString() }).ToArray(); + _entitySerializer.Serialize(m).ToDataString() }).ToArray(); db.BulkInsertRecords(items); processed += items.Length; } while (processed < total); @@ -1962,7 +1964,7 @@ WHERE cmsContentXml.nodeId IN ( do { var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml = EntityXmlSerializer.Serialize(_serviceContext.DataTypeService, _serviceContext.LocalizationService, m).ToDataString() }).ToArray(); + var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml = _entitySerializer.Serialize(m).ToDataString() }).ToArray(); db.BulkInsertRecords(items); processed += items.Length; } while (processed < total); diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index 5d013d7e79..6337db67f9 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -298,7 +298,7 @@ namespace Umbraco.Web.Services //we need to interrogate the attributes for the data. Would be better to have a base class that contains //metadata populated by the attribute. Oh well i guess. var attrs = types.Select(x => x.GetCustomAttributes(false).Single()); - return Enumerable.ToArray
(attrs.Select(x => new Section(x.Name, x.Alias, x.SortOrder))); + return attrs.Select(x => new Section(x.Name, x.Alias, x.SortOrder)).ToArray(); }); } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 36f0a835b1..fdf7f48201 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1144,9 +1144,6 @@ - - - @@ -1231,7 +1228,6 @@ Code - FeedProxy.aspx diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 15ea222bda..9d7fe77e7b 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -14,18 +14,18 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Packaging; using Umbraco.Core.Services.Implement; using Umbraco.Core.Xml; using Umbraco.Web._Legacy.Packager.PackageInstance; using File = System.IO.File; -using PackageAction = Umbraco.Web._Legacy.Packager.PackageInstance.PackageAction; namespace Umbraco.Web._Legacy.Packager { /// /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. /// - /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documenttypes (etc.) + /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documentTypes (etc.) /// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.) /// /// Partly implemented, import of packages is done, the export is *under construction*. @@ -420,7 +420,7 @@ namespace Umbraco.Web._Legacy.Packager var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); foreach (var contentType in contentTypes) { - insPack.Data.Documenttypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); + insPack.Data.DocumentTypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); //saveNeeded = true; } } @@ -510,7 +510,7 @@ namespace Umbraco.Web._Legacy.Packager if (alias.IsNullOrWhiteSpace() == false) { - PackageAction.RunPackageAction(insPack.Data.Name, alias, n); + Current.PackageActionRunner.RunPackageAction(insPack.Data.Name, alias, n); } } } diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs index 3bfcdd3f86..deff3b2ffd 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs @@ -7,11 +7,13 @@ using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using File = System.IO.File; namespace Umbraco.Web._Legacy.Packager.PackageInstance { + //TODO: Fix this class , service + model + internal? public class CreatedPackage { @@ -22,14 +24,13 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance return pack; } - public static CreatedPackage MakeNew(string name) + public static CreatedPackage MakeNew(string name, Core.Models.Packaging.PackageDefinition packageData = null) { var pack = new CreatedPackage { - Data = data.MakeNew(name, IOHelper.MapPath(Settings.CreatedPackagesSettings)) + Data = packageData ?? data.MakeNew(name, IOHelper.MapPath(Settings.CreatedPackagesSettings)) }; - return pack; } @@ -43,7 +44,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance data.Delete(this.Data.Id, IOHelper.MapPath(Settings.CreatedPackagesSettings)); } - public PackageInstance Data { get; set; } + public Core.Models.Packaging.PackageDefinition Data { get; set; } public static List GetAllCreatedPackages() { @@ -81,7 +82,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance } - public void Publish() + public void Publish(IEntityXmlSerializer serializer) { var package = this; @@ -118,7 +119,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance //var umbDocument = new Document(contentNodeId); //var x = umbDocument.ToXml(_packageManifest, pack.ContentLoadChildNodes); var udoc = Current.Services.ContentService.GetById(contentNodeId); - var xe = pack.ContentLoadChildNodes ? udoc.ToDeepXml(Current.Services.PackagingService) : udoc.ToXml(Current.Services.PackagingService); + var xe = pack.ContentLoadChildNodes ? udoc.ToDeepXml(serializer) : udoc.ToXml(serializer); var x = xe.GetXmlNode(_packageManifest); documentSet.AppendChild(x); @@ -188,7 +189,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance //Document types.. var dtl = new List(); var docTypes = _packageManifest.CreateElement("DocumentTypes"); - foreach (var dtId in pack.Documenttypes) + foreach (var dtId in pack.DocumentTypes) { if (int.TryParse(dtId, out outInt)) { @@ -200,11 +201,9 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance } } - var exporter = new EntityXmlSerializer(); - foreach (var d in dtl) { - var xml = exporter.Serialize(Current.Services.DataTypeService, Current.Services.ContentTypeService, d); + var xml = serializer.Serialize(d); var xNode = xml.GetXmlNode(); var n = (XmlElement) _packageManifest.ImportNode(xNode, true); docTypes.AppendChild(n); @@ -220,7 +219,6 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance { var t = Current.Services.FileService.GetTemplate(outInt); - var serializer = new EntityXmlSerializer(); var serialized = serializer.Serialize(t); var n = serialized.GetXmlNode(_packageManifest); @@ -241,16 +239,16 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance } AppendElement(stylesheets); - //Macros - var macros = _packageManifest.CreateElement("Macros"); - foreach (var macroId in pack.Macros) - { - if (int.TryParse(macroId, out outInt)) - { - macros.AppendChild(PackagerUtility.Macro(int.Parse(macroId), true, localPath, _packageManifest)); - } - } - AppendElement(macros); + ////Macros + //var macros = _packageManifest.CreateElement("Macros"); + //foreach (var macroId in pack.Macros) + //{ + // if (int.TryParse(macroId, out outInt)) + // { + // macros.AppendChild(PackagerUtility.Macro(int.Parse(macroId), true, localPath, _packageManifest)); + // } + //} + //AppendElement(macros); //Dictionary Items var dictionaryItems = _packageManifest.CreateElement("DictionaryItems"); @@ -259,8 +257,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance if (int.TryParse(dictionaryId, out outInt)) { var di = Current.Services.LocalizationService.GetDictionaryItemById(outInt); - var entitySerializer = new EntityXmlSerializer(); - var xmlNode = entitySerializer.Serialize(di).GetXmlNode(_packageManifest); + var xmlNode = serializer.Serialize(di, false).GetXmlNode(_packageManifest); dictionaryItems.AppendChild(xmlNode); } } @@ -274,7 +271,6 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance { var lang = Current.Services.LocalizationService.GetLanguageById(outInt); - var serializer = new EntityXmlSerializer(); var xml = serializer.Serialize(lang); var n = xml.GetXmlNode(_packageManifest); @@ -328,7 +324,10 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance AppendElement(actions); } } - catch { } + catch + { + //TODO: Log!? + } } var manifestFileName = localPath + "/package.xml"; diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs deleted file mode 100644 index b920c85a9f..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/IPackageInstance.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Umbraco.Web._Legacy.Packager.PackageInstance{ - public interface IPackageInstance { - string Actions { get; set; } - string Author { get; set; } - string AuthorUrl { get; set; } - bool ContentLoadChildNodes { get; set; } - string ContentNodeId { get; set; } - System.Collections.Generic.List Documenttypes { get; set; } - System.Collections.Generic.List Files { get; set; } - string Folder { get; set; } - bool HasUpdate { get; set; } - int Id { get; set; } - string License { get; set; } - string LicenseUrl { get; set; } - string LoadControl { get; set; } - System.Collections.Generic.List Macros { get; set; } - string Name { get; set; } - string PackageGuid { get; set; } - string PackagePath { get; set; } - string Readme { get; set; } - string RepositoryGuid { get; set; } - System.Collections.Generic.List Stylesheets { get; set; } - System.Collections.Generic.List Templates { get; set; } - string Url { get; set; } - string Version { get; set; } - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs index 5842a456e5..8c106f142d 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs @@ -53,7 +53,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance List val = new List(); - foreach (PackageInstance pack in data.GetAllPackages(IOHelper.MapPath(Settings.InstalledPackagesSettings))) + foreach (Core.Models.Packaging.PackageDefinition pack in data.GetAllPackages(IOHelper.MapPath(Settings.InstalledPackagesSettings))) { InstalledPackage insPackage = new InstalledPackage(); insPackage.Data = pack; @@ -63,8 +63,8 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance return val; } - private PackageInstance m_data; - public PackageInstance Data + private Core.Models.Packaging.PackageDefinition m_data; + public Core.Models.Packaging.PackageDefinition Data { get { return m_data; } set { m_data = value; } @@ -156,7 +156,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance { var macros = TryGetIntegerIds(Data.Macros).Select(macroService.GetById).ToList(); var templates = TryGetIntegerIds(Data.Templates).Select(fileService.GetTemplate).ToList(); - var contentTypes = TryGetIntegerIds(Data.Documenttypes).Select(contentTypeService.Get).ToList(); // fixme - media types? + var contentTypes = TryGetIntegerIds(Data.DocumentTypes).Select(contentTypeService.Get).ToList(); // fixme - media types? var dataTypes = TryGetIntegerIds(Data.DataTypes).Select(dataTypeService.GetDataType).ToList(); var dictionaryItems = TryGetIntegerIds(Data.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList(); var languages = TryGetIntegerIds(Data.Languages).Select(localizationService.GetLanguageById).ToList(); diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs deleted file mode 100644 index 8ec3c21bdb..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackageInstance.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Runtime.Serialization; - -namespace Umbraco.Web._Legacy.Packager.PackageInstance -{ - [DataContract(Name = "packageInstance")] - public class PackageInstance - { - [DataMember(Name = "id")] - public int Id { get; set; } - - [DataMember(Name = "repositoryGuid")] - public string RepositoryGuid { get; set; } - - [DataMember(Name = "packageGuid")] - public string PackageGuid { get; set; } - - [DataMember(Name = "hasUpdate")] - public bool HasUpdate { get; set; } - - [DataMember(Name = "name")] - [Required] - public string Name { get; set; } - - [DataMember(Name = "url")] - [Required] - [Url] - public string Url { get; set; } - - [DataMember(Name = "folder")] - public string Folder { get; set; } - - [DataMember(Name = "packagePath")] - public string PackagePath { get; set; } - - [DataMember(Name = "version")] - [Required] - public string Version { get; set; } - - /// - /// The minimum umbraco version that this package requires - /// - [DataMember(Name = "umbracoVersion")] - public Version UmbracoVersion { get; set; } - - [DataMember(Name = "author")] - [Required] - public string Author { get; set; } - - [DataMember(Name = "authorUrl")] - [Required] - [Url] - public string AuthorUrl { get; set; } - - [DataMember(Name = "license")] - public string License { get; set; } - - [DataMember(Name = "licenseUrl")] - public string LicenseUrl { get; set; } - - [DataMember(Name = "readme")] - public string Readme { get; set; } - - [DataMember(Name = "contentLoadChildNodes")] - public bool ContentLoadChildNodes { get; set; } - - [DataMember(Name = "contentNodeId")] - public string ContentNodeId { get; set; } - - [DataMember(Name = "macros")] - public List Macros { get; set; } - - [DataMember(Name = "languages")] - public List Languages { get; set; } - - [DataMember(Name = "dictionaryItems")] - public List DictionaryItems { get; set; } - - [DataMember(Name = "templates")] - public List Templates { get; set; } - - [DataMember(Name = "documenttypes")] - public List Documenttypes { get; set; } - - [DataMember(Name = "stylesheets")] - public List Stylesheets { get; set; } - - [DataMember(Name = "files")] - public List Files { get; set; } - - [DataMember(Name = "loadControl")] - public string LoadControl { get; set; } - - [DataMember(Name = "actions")] - public string Actions { get; set; } - - [DataMember(Name = "dataTypes")] - public List DataTypes { get; set; } - - [DataMember(Name = "iconUrl")] - public string IconUrl { get; set; } - - public PackageInstance() - { - Name = string.Empty; - Url = string.Empty; - Folder = string.Empty; - PackagePath = string.Empty; - Version = string.Empty; - UmbracoVersion = null; - Author = string.Empty; - AuthorUrl = string.Empty; - License = string.Empty; - LicenseUrl = string.Empty; - Readme = string.Empty; - ContentNodeId = string.Empty; - IconUrl = string.Empty; - Macros = new List(); - Languages = new List(); - DictionaryItems = new List(); - Templates = new List(); - Documenttypes = new List(); - Stylesheets = new List(); - Files = new List(); - LoadControl = string.Empty; - DataTypes = new List(); - ContentLoadChildNodes = false; - } - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs index d972977bad..af32e8c80a 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; namespace Umbraco.Web._Legacy.Packager.PackageInstance { @@ -22,7 +23,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance /// The packinstance. /// The xml document. /// - public static XmlNode PackageInfo(PackageInstance pack, XmlDocument doc) + public static XmlNode PackageInfo(Core.Models.Packaging.PackageDefinition pack, XmlDocument doc) { XmlNode info = doc.CreateElement("info"); @@ -60,31 +61,6 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance return info; } - - /// - /// Converts an umbraco template to a package xml node - /// - /// The template id. - /// The xml doc. - /// - public static XmlNode Template(int templateId, XmlDocument doc) - { - var tmpl = Current.Services.FileService.GetTemplate(templateId); - //Template tmpl = new Template(templateId); - - XmlNode template = doc.CreateElement("Template"); - template.AppendChild(CreateNode("Name", tmpl.Name, doc)); - template.AppendChild(CreateNode("Alias", tmpl.Alias, doc)); - - //if (tmpl.MasterTemplate != 0) - if (string.IsNullOrWhiteSpace(tmpl.MasterTemplateAlias) == false) - template.AppendChild(CreateNode("Master", tmpl.MasterTemplateAlias, doc)); - - template.AppendChild(CreateNode("Design", "", doc)); - - return template; - } - /// /// Converts a umbraco stylesheet to a package xml node /// @@ -118,29 +94,6 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance return stylesheet; } - /// - /// Converts a macro to a package xml node - /// - /// The macro id. - /// if set to true [append file]. - /// The package directory. - /// The doc. - /// - public static XmlNode Macro(int macroId, bool appendFile, string packageDirectory, XmlDocument doc) - { - var mcr = Current.Services.MacroService.GetById(macroId); - - if (appendFile) - { - if (!string.IsNullOrEmpty(mcr.MacroSource)) - AppendFileToManifest(mcr.MacroSource, packageDirectory, doc); - } - - var serializer = new EntityXmlSerializer(); - var xml = serializer.Serialize(mcr); - return xml.GetXmlNode(doc); - } - /// /// Appends a file to package manifest and copies the file to the correct folder. diff --git a/src/Umbraco.Web/_Legacy/Packager/Settings.cs b/src/Umbraco.Web/_Legacy/Packager/Settings.cs index 57ab4b9ea4..92b0ae030a 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Settings.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Settings.cs @@ -6,69 +6,11 @@ namespace Umbraco.Web._Legacy.Packager { public class Settings { + public static string InstalledPackagesSettings => SystemDirectories.Packages + IOHelper.DirSepChar + "installedPackages.config"; - public static string PackagerRoot - { - get { return SystemDirectories.Packages; } - } - - public static string PackagesStorage - { - get { return SystemDirectories.Packages + IOHelper.DirSepChar + "created"; } - } - - public static string InstalledPackagesStorage - { - get { return SystemDirectories.Packages + IOHelper.DirSepChar + "installed"; } - } - - public static string InstalledPackagesSettings - { - get { return SystemDirectories.Packages + IOHelper.DirSepChar + "installed" + IOHelper.DirSepChar + "installedPackages.config"; } - } - - public static string CreatedPackagesSettings - { - get { return SystemDirectories.Packages + IOHelper.DirSepChar + "created" + IOHelper.DirSepChar + "createdPackages.config"; } - } - - public static string PackageFileExtension - { - get { return "zip"; } - } - - public static bool HasFileAccess(ref Exception exp) - { - bool hasAccess = false; - StreamWriter sw1 = null; - StreamWriter sw2 = null; - try - { - sw1 = System.IO.File.AppendText(IOHelper.MapPath(InstalledPackagesSettings)); - sw1.Close(); - - sw2 = System.IO.File.AppendText(IOHelper.MapPath(CreatedPackagesSettings)); - sw1.Close(); - - System.IO.Directory.CreateDirectory(IOHelper.MapPath(PackagesStorage) + IOHelper.DirSepChar + "__testFolder__"); - System.IO.Directory.CreateDirectory(IOHelper.MapPath(InstalledPackagesStorage) + IOHelper.DirSepChar + "__testFolder__"); - - System.IO.Directory.Delete(IOHelper.MapPath(PackagesStorage) + IOHelper.DirSepChar + "__testFolder__", true); - System.IO.Directory.Delete(IOHelper.MapPath(InstalledPackagesStorage) + IOHelper.DirSepChar + "__testFolder__", true); - - hasAccess = true; - } - finally - { - if (sw1 != null) - sw1.Close(); - if (sw2 != null) - sw2.Close(); - } - - return hasAccess; - } + public static string CreatedPackagesSettings => SystemDirectories.Packages + IOHelper.DirSepChar + "createdPackages.config"; + public static string PackageFileExtension => "zip"; } diff --git a/src/Umbraco.Web/_Legacy/Packager/data.cs b/src/Umbraco.Web/_Legacy/Packager/data.cs index 962b7d5ed4..1882c151d2 100644 --- a/src/Umbraco.Web/_Legacy/Packager/data.cs +++ b/src/Umbraco.Web/_Legacy/Packager/data.cs @@ -23,20 +23,12 @@ namespace Umbraco.Web._Legacy.Packager //do some error checking and create the folders/files if they don't exist if (!File.Exists(dataSource)) { - if (!Directory.Exists(IOHelper.MapPath(Settings.PackagerRoot))) + if (!Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages))) { - Directory.CreateDirectory(IOHelper.MapPath(Settings.PackagerRoot)); - } - if (!Directory.Exists(IOHelper.MapPath(Settings.PackagesStorage))) - { - Directory.CreateDirectory(IOHelper.MapPath(Settings.PackagesStorage)); - } - if (!Directory.Exists(IOHelper.MapPath(Settings.InstalledPackagesStorage))) - { - Directory.CreateDirectory(IOHelper.MapPath(Settings.InstalledPackagesStorage)); + Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); } - using (StreamWriter sw = File.CreateText(dataSource)) + using (var sw = File.CreateText(dataSource)) { sw.Write($@"{Environment.NewLine}{Environment.NewLine}"); sw.Flush(); @@ -85,7 +77,7 @@ namespace Umbraco.Web._Legacy.Packager return Source.SelectSingleNode("/packages/package [@packageGuid = '" + guid + "']"); } - public static PackageInstance.PackageInstance MakeNew(string Name, string dataSource) + public static Core.Models.Packaging.PackageDefinition MakeNew(string name, string dataSource) { Reload(dataSource); @@ -101,7 +93,7 @@ namespace Umbraco.Web._Legacy.Packager instance.Attributes.Append(XmlHelper.AddAttribute(Source, "id", maxId.ToString())); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "version", "")); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "url", "")); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "name", Name)); + instance.Attributes.Append(XmlHelper.AddAttribute(Source, "name", name)); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "folder", Guid.NewGuid().ToString())); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "packagepath", "")); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "repositoryGuid", "")); @@ -137,7 +129,7 @@ namespace Umbraco.Web._Legacy.Packager instance.AppendChild(XmlHelper.AddTextNode(Source, "templates", "")); instance.AppendChild(XmlHelper.AddTextNode(Source, "stylesheets", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "documenttypes", "")); + instance.AppendChild(XmlHelper.AddTextNode(Source, "documentTypes", "")); instance.AppendChild(XmlHelper.AddTextNode(Source, "macros", "")); instance.AppendChild(XmlHelper.AddTextNode(Source, "files", "")); instance.AppendChild(XmlHelper.AddTextNode(Source, "languages", "")); @@ -151,26 +143,26 @@ namespace Umbraco.Web._Legacy.Packager return retVal; } - public static PackageInstance.PackageInstance Package(int id, string datasource) + public static Core.Models.Packaging.PackageDefinition Package(int id, string datasource) { return ConvertXmlToPackage(GetFromId(id, datasource, true)); } - public static PackageInstance.PackageInstance Package(string guid, string datasource) + public static Core.Models.Packaging.PackageDefinition Package(string guid, string datasource) { XmlNode node = GetFromGuid(guid, datasource, true); if (node != null) return ConvertXmlToPackage(node); else - return new PackageInstance.PackageInstance(); + return new Core.Models.Packaging.PackageDefinition(); } - public static List GetAllPackages(string dataSource) + public static List GetAllPackages(string dataSource) { Reload(dataSource); XmlNodeList nList = data.Source.SelectNodes("packages/package"); - List retVal = new List(); + List retVal = new List(); for (int i = 0; i < nList.Count; i++) { @@ -187,9 +179,9 @@ namespace Umbraco.Web._Legacy.Packager return retVal; } - private static PackageInstance.PackageInstance ConvertXmlToPackage(XmlNode n) + private static Core.Models.Packaging.PackageDefinition ConvertXmlToPackage(XmlNode n) { - PackageInstance.PackageInstance retVal = new PackageInstance.PackageInstance(); + Core.Models.Packaging.PackageDefinition retVal = new Core.Models.Packaging.PackageDefinition(); if (n != null) { @@ -227,7 +219,7 @@ namespace Umbraco.Web._Legacy.Packager retVal.Macros = new List(SafeNodeValue(n.SelectSingleNode("macros")).Trim(',').Split(',')); retVal.Templates = new List(SafeNodeValue(n.SelectSingleNode("templates")).Trim(',').Split(',')); retVal.Stylesheets = new List(SafeNodeValue(n.SelectSingleNode("stylesheets")).Trim(',').Split(',')); - retVal.Documenttypes = new List(SafeNodeValue(n.SelectSingleNode("documenttypes")).Trim(',').Split(',')); + retVal.DocumentTypes = new List(SafeNodeValue(n.SelectSingleNode("documentTypes")).Trim(',').Split(',')); retVal.Languages = new List(SafeNodeValue(n.SelectSingleNode("languages")).Trim(',').Split(',')); retVal.DictionaryItems = new List(SafeNodeValue(n.SelectSingleNode("dictionaryitems")).Trim(',').Split(',')); retVal.DataTypes = new List(SafeNodeValue(n.SelectSingleNode("datatypes")).Trim(',').Split(',')); @@ -263,7 +255,7 @@ namespace Umbraco.Web._Legacy.Packager } - public static void Save(PackageInstance.PackageInstance package, string dataSource) + public static void Save(Core.Models.Packaging.PackageDefinition package, string dataSource) { Reload(dataSource); var xmlDef = GetFromId(package.Id, dataSource, false); @@ -311,7 +303,7 @@ namespace Umbraco.Web._Legacy.Packager XmlHelper.SetTextNode(Source, xmlDef, "macros", JoinList(package.Macros, ',')); XmlHelper.SetTextNode(Source, xmlDef, "templates", JoinList(package.Templates, ',')); XmlHelper.SetTextNode(Source, xmlDef, "stylesheets", JoinList(package.Stylesheets, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "documenttypes", JoinList(package.Documenttypes, ',')); + XmlHelper.SetTextNode(Source, xmlDef, "documentTypes", JoinList(package.DocumentTypes, ',')); XmlHelper.SetTextNode(Source, xmlDef, "languages", JoinList(package.Languages, ',')); XmlHelper.SetTextNode(Source, xmlDef, "dictionaryitems", JoinList(package.DictionaryItems, ',')); XmlHelper.SetTextNode(Source, xmlDef, "datatypes", JoinList(package.DataTypes, ',')); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs deleted file mode 100644 index 47980f2808..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/CreatedPackageTasks.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Umbraco.Core.Logging; -using Umbraco.Web.UI; -using Umbraco.Core; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Umbraco.Web._Legacy.Packager.PackageInstance; -using Umbraco.Web._Legacy.UI; - -namespace Umbraco.Web -{ - public class CreatedPackageTasks : LegacyDialogTask - { - - public override bool PerformSave() - { - Current.Logger.Info("Xml save started"); - int id = CreatedPackage.MakeNew(Alias).Data.Id; - _returnUrl = string.Format("developer/packages/editPackage.aspx?id={0}", id); - return true; - } - - public override bool PerformDelete() - { - // we need to grab the id from the alias as the new tree needs to prefix the NodeID with "package_" - if (ParentID == 0) - { - ParentID = int.Parse(Alias.Substring("package_".Length)); - } - CreatedPackage.GetById(ParentID).Delete(); - return true; - } - - private string _returnUrl = ""; - - public override string ReturnUrl - { - get { return _returnUrl; } - } - - public override string AssignedApp - { - get { return Constants.Applications.Packages.ToString(); } - } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs index 645aa088f2..3b863895a4 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs @@ -10,6 +10,8 @@ using System.Xml; using umbraco.controls; using Umbraco.Core; using Umbraco.Core.IO; +using Umbraco.Core.Models.Packaging; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.UI; using Umbraco.Web.UI.Pages; using Umbraco.Web._Legacy.Packager.PackageInstance; @@ -32,7 +34,7 @@ namespace umbraco.presentation.developer.packages public Umbraco.Web._Legacy.Controls.TabPage packageActions; protected ContentPicker cp; - private PackageInstance pack; + private PackageDefinition pack; private CreatedPackage createdPackage; protected void Page_Load(object sender, EventArgs e) @@ -102,7 +104,7 @@ namespace umbraco.presentation.developer.packages foreach (var dc in nContentTypes) { ListItem li = new ListItem(dc.Name, dc.Id.ToString()); - if (pack.Documenttypes.Contains(dc.Id.ToString())) + if (pack.DocumentTypes.Contains(dc.Id.ToString())) li.Selected = true; documentTypes.Items.Add(li); @@ -223,41 +225,41 @@ namespace umbraco.presentation.developer.packages e.IsValid = true; } - protected void saveOrPublish(object sender, CommandEventArgs e) - { + //protected void saveOrPublish(object sender, CommandEventArgs e) + //{ - if (!Page.IsValid) - { - this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, "Saved failed.", "Some fields have not been filled-out correctly"); - } - else - { - if (e.CommandName == "save") - SavePackage(true); + // if (!Page.IsValid) + // { + // this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, "Saved failed.", "Some fields have not been filled-out correctly"); + // } + // else + // { + // if (e.CommandName == "save") + // SavePackage(true); - if (e.CommandName == "publish") - { - SavePackage(false); - int packageID = int.Parse(Request.QueryString["id"]); - //string packFileName = cms.businesslogic.packager. Publish.publishPackage(packageID); + // if (e.CommandName == "publish") + // { + // SavePackage(false); + // int packageID = int.Parse(Request.QueryString["id"]); + // //string packFileName = cms.businesslogic.packager. Publish.publishPackage(packageID); - createdPackage.Publish(); + // createdPackage.Publish(); - if (!string.IsNullOrEmpty(pack.PackagePath)) - { + // if (!string.IsNullOrEmpty(pack.PackagePath)) + // { - packageUmbFile.Text = "   Download"; + // packageUmbFile.Text = "   Download"; - this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Success, "Package saved and published", ""); - } - else - { - this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, "Save failed", "check your umbraco log."); - } - } - } - } + // this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Success, "Package saved and published", ""); + // } + // else + // { + // this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, "Save failed", "check your umbraco log."); + // } + // } + // } + //} private void SavePackage(bool showNotification) @@ -300,7 +302,7 @@ namespace umbraco.presentation.developer.packages if (li.Selected) tmpDoctypes += li.Value + ","; } - pack.Documenttypes = new List(tmpDoctypes.Trim(',').Split(',')); + pack.DocumentTypes = new List(tmpDoctypes.Trim(',').Split(',')); string tmpMacros = ""; @@ -361,7 +363,7 @@ namespace umbraco.presentation.developer.packages if (newPath.Trim() != "") { CreatedPackage createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - PackageInstance pack = createdPackage.Data; + PackageDefinition pack = createdPackage.Data; pack.Files.Add(newPath); @@ -388,7 +390,7 @@ namespace umbraco.presentation.developer.packages } CreatedPackage createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - PackageInstance pack = createdPackage.Data; + PackageDefinition pack = createdPackage.Data; pack.Files = new List(tmpFilePathString.Trim('�').Split('�')); pack.Files.TrimExcess(); From b8d2309b9c1fae3e21a21d86744d27a10a997056 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 10 Jan 2019 17:18:47 +1100 Subject: [PATCH 063/223] Gets the IPackageBuilder working and tested, now the controller can create and update packages, validation is also working, need to do some more tests for adding other entities , removes more of the old packaging code. --- .../Composing/Composers/ServicesComposer.cs | 7 +- src/Umbraco.Core/IO/SystemDirectories.cs | 4 +- .../Models/Packaging/PackageDefinition.cs | 36 +- src/Umbraco.Core/Packaging/IPackageBuilder.cs | 30 + .../Packaging/IPackageCreation.cs | 22 - .../{PackageCreation.cs => PackageBuilder.cs} | 190 ++++-- .../Packaging}/RequirementsType.cs | 2 +- .../Services/IPackagingService.cs | 20 +- .../Services/Implement/PackagingService.cs | 16 +- src/Umbraco.Core/Umbraco.Core.csproj | 5 +- .../Composing/TypeFinderTests.cs | 2 +- .../Services/PackagingServiceTests.cs | 3 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 3 + .../src/common/resources/package.resource.js | 17 +- .../src/common/services/formhelper.service.js | 2 + .../services/umbrequesthelper.service.js | 2 + .../content/content.delete.controller.js | 1 + .../views/media/media.delete.controller.js | 1 + .../src/views/packages/edit.controller.js | 58 +- .../src/views/packages/edit.html | 17 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 10 - .../Umbraco/config/create/UI.Release.xml | 28 - .../Umbraco/config/create/UI.xml | 28 - .../Packages/DirectoryBrowser.aspx.cs | 140 ---- .../DirectoryBrowser.aspx.designer.cs | 42 -- .../developer/Packages/directoryBrowser.aspx | 26 - .../developer/Packages/editPackage.aspx | 232 ------- .../Umbraco/developer/Packages/installer.aspx | 10 - .../developer/Packages/editPackage.aspx | 232 ------- src/Umbraco.Web/Editors/PackageController.cs | 55 +- .../Editors/PackageInstallController.cs | 3 +- .../Controllers/InstallPackageController.cs | 2 +- .../InstallSteps/StarterKitDownloadStep.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 13 - src/Umbraco.Web/_Legacy/Packager/Installer.cs | 17 +- .../PackageInstance/CreatedPackage.cs | 387 ----------- .../PackageInstance/InstalledPackage.cs | 2 +- .../PackageInstance/PackagerUtility.cs | 279 -------- src/Umbraco.Web/_Legacy/Packager/Settings.cs | 4 - src/Umbraco.Web/_Legacy/Packager/data.cs | 18 +- .../developer/Packages/editPackage.aspx | 232 ------- .../developer/Packages/editPackage.aspx.cs | 453 ------------- .../Packages/editPackage.aspx.designer.cs | 609 ------------------ 44 files changed, 333 insertions(+), 2931 deletions(-) create mode 100644 src/Umbraco.Core/Packaging/IPackageBuilder.cs delete mode 100644 src/Umbraco.Core/Packaging/IPackageCreation.cs rename src/Umbraco.Core/Packaging/{PackageCreation.cs => PackageBuilder.cs} (72%) rename src/{Umbraco.Web/_Legacy/Packager => Umbraco.Core/Packaging}/RequirementsType.cs (65%) delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.designer.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Packages/directoryBrowser.aspx delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Packages/editPackage.aspx delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Packages/installer.aspx delete mode 100644 src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx delete mode 100644 src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.designer.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 6133d63377..6395a2c6db 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -60,8 +60,11 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(); composition.RegisterUnique(); - composition.RegisterUnique(); - + composition.RegisterUnique(factory => + new PackageBuilder( //we are using a factory because there are optional ctor args + factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), + factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), + factory.GetInstance(), factory.GetInstance())); //TODO: These are replaced in the web project - we need to declare them so that // something is wired up, just not sure this is very nice but will work for now. diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index 183d48e3d9..94aa7b16cc 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -43,9 +43,9 @@ namespace Umbraco.Core.IO [Obsolete("Only used by legacy load balancing which is obsolete and should be removed")] public static string WebServices => IOHelper.ReturnPath("umbracoWebservicesPath", Umbraco.EnsureEndsWith("/") + "webservices"); - public static string Packages => Data + IOHelper.DirSepChar + "packages"; + public static string Packages => Data + "/packages"; - public static string Preview => Data + IOHelper.DirSepChar + "preview"; + public static string Preview => Data + "/preview"; private static string _root; diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index 783b11235f..16934dc4c4 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -11,15 +11,8 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "id")] public int Id { get; set; } - //TODO: I don't see why this is necessary - [DataMember(Name = "repositoryGuid")] - public string RepositoryGuid { get; set; } - [DataMember(Name = "packageGuid")] - public string PackageGuid { get; set; } - - [DataMember(Name = "hasUpdate")] - public bool HasUpdate { get; set; } + public Guid PackageId { get; set; } [DataMember(Name = "name")] [Required] @@ -30,21 +23,24 @@ namespace Umbraco.Core.Models.Packaging [Url] public string Url { get; set; } = string.Empty; + /// + /// This is a generated GUID which is used to determine a temporary folder name for processing the package + /// [DataMember(Name = "folder")] - public string Folder { get; set; } = string.Empty; + public Guid FolderId { get; set; } [DataMember(Name = "packagePath")] public string PackagePath { get; set; } = string.Empty; [DataMember(Name = "version")] [Required] - public string Version { get; set; } = string.Empty; + public string Version { get; set; } = "1.0.0"; /// /// The minimum umbraco version that this package requires /// [DataMember(Name = "umbracoVersion")] - public Version UmbracoVersion { get; set; } + public Version UmbracoVersion { get; set; } = Configuration.UmbracoVersion.Current; [DataMember(Name = "author")] [Required] @@ -65,31 +61,31 @@ namespace Umbraco.Core.Models.Packaging public string Readme { get; set; } = string.Empty; [DataMember(Name = "contentLoadChildNodes")] - public bool ContentLoadChildNodes { get; set; } = false; + public bool ContentLoadChildNodes { get; set; } [DataMember(Name = "contentNodeId")] public string ContentNodeId { get; set; } = string.Empty; [DataMember(Name = "macros")] - public List Macros { get; set; } = new List(); + public IList Macros { get; set; } = new List(); [DataMember(Name = "languages")] - public List Languages { get; set; } = new List(); + public IList Languages { get; set; } = new List(); [DataMember(Name = "dictionaryItems")] - public List DictionaryItems { get; set; } = new List(); + public IList DictionaryItems { get; set; } = new List(); [DataMember(Name = "templates")] - public List Templates { get; set; } = new List(); + public IList Templates { get; set; } = new List(); [DataMember(Name = "documentTypes")] - public List DocumentTypes { get; set; } = new List(); + public IList DocumentTypes { get; set; } = new List(); [DataMember(Name = "stylesheets")] - public List Stylesheets { get; set; } = new List(); + public IList Stylesheets { get; set; } = new List(); [DataMember(Name = "files")] - public List Files { get; set; } = new List(); + public IList Files { get; set; } = new List(); //TODO: Change this to angular view [DataMember(Name = "loadControl")] @@ -99,7 +95,7 @@ namespace Umbraco.Core.Models.Packaging public string Actions { get; set; } [DataMember(Name = "dataTypes")] - public List DataTypes { get; set; } = new List(); + public IList DataTypes { get; set; } = new List(); [DataMember(Name = "iconUrl")] public string IconUrl { get; set; } = string.Empty; diff --git a/src/Umbraco.Core/Packaging/IPackageBuilder.cs b/src/Umbraco.Core/Packaging/IPackageBuilder.cs new file mode 100644 index 0000000000..5a7449545f --- /dev/null +++ b/src/Umbraco.Core/Packaging/IPackageBuilder.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Models.Packaging; + +namespace Umbraco.Core.Packaging +{ + /// + /// Creates packages + /// + public interface IPackageBuilder + { + IEnumerable GetAll(); + PackageDefinition GetById(int id); + void Delete(int id); + + /// + /// Persists a package definition to storage + /// + /// + /// true if creating/updating the package was successful, otherwise false + /// + bool SavePackage(PackageDefinition definition); + + /// + /// Creates the package file and returns it's physical path + /// + /// + string ExportPackage(PackageDefinition definition); + } +} diff --git a/src/Umbraco.Core/Packaging/IPackageCreation.cs b/src/Umbraco.Core/Packaging/IPackageCreation.cs deleted file mode 100644 index 35397299a7..0000000000 --- a/src/Umbraco.Core/Packaging/IPackageCreation.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Umbraco.Core.Models.Packaging; - -namespace Umbraco.Core.Packaging -{ - /// - /// Creates packages - /// - public interface IPackageCreation - { - /// - /// Persists a package definition to storage - /// - /// - void SavePackageDefinition(PackageDefinition definition); - - /// - /// Creates the package file and returns it's physical path - /// - /// - string ExportPackageDefinition(PackageDefinition definition); - } -} diff --git a/src/Umbraco.Core/Packaging/PackageCreation.cs b/src/Umbraco.Core/Packaging/PackageBuilder.cs similarity index 72% rename from src/Umbraco.Core/Packaging/PackageCreation.cs rename to src/Umbraco.Core/Packaging/PackageBuilder.cs index 615b844101..cc77f9bc78 100644 --- a/src/Umbraco.Core/Packaging/PackageCreation.cs +++ b/src/Umbraco.Core/Packaging/PackageBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.IO; using System.IO.Compression; using System.Linq; @@ -14,7 +15,7 @@ using File = System.IO.File; namespace Umbraco.Core.Packaging { - internal class PackageCreation : IPackageCreation + internal class PackageBuilder : IPackageBuilder { private readonly IContentService _contentService; private readonly IContentTypeService _contentTypeService; @@ -24,11 +25,15 @@ namespace Umbraco.Core.Packaging private readonly ILocalizationService _languageService; private readonly IEntityXmlSerializer _serializer; private readonly ILogger _logger; - - public PackageCreation(IContentService contentService, IContentTypeService contentTypeService, + private readonly string _mediaFolderPath; + private readonly string _packagesFolderPath; + private readonly string _tempFolderPath; + + public PackageBuilder(IContentService contentService, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, IMacroService macroService, ILocalizationService languageService, - IEntityXmlSerializer serializer, ILogger logger) + IEntityXmlSerializer serializer, ILogger logger, + string tempFolderPath = null, string packagesFolderPath = null, string mediaFolderPath = null) { _contentService = contentService; _contentTypeService = contentTypeService; @@ -38,49 +43,87 @@ namespace Umbraco.Core.Packaging _languageService = languageService; _serializer = serializer; _logger = logger; + + _tempFolderPath = tempFolderPath ?? SystemDirectories.Data + "/TEMP/PackageFiles"; + _packagesFolderPath = packagesFolderPath ?? SystemDirectories.Packages; + _mediaFolderPath = mediaFolderPath ?? SystemDirectories.Media + "/created-packages"; } - public static string CreatedPackagesFile => SystemDirectories.Packages + IOHelper.DirSepChar + "createdPackages.config"; + private string CreatedPackagesFile => _packagesFolderPath.EnsureEndsWith('/') + "createdPackages.config"; - public void SavePackageDefinition(PackageDefinition definition) + public IEnumerable GetAll() + { + var packagesXml = EnsureStorage(out _); + foreach (var packageXml in packagesXml.Root.Elements("package")) + yield return XmlToPackageDefinition(packageXml); + } + + public PackageDefinition GetById(int id) + { + var packagesXml = EnsureStorage(out _); + var packageXml = packagesXml.Root.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); + return packageXml == null ? null : XmlToPackageDefinition(packageXml); + } + + public void Delete(int id) + { + var packagesXml = EnsureStorage(out var packagesFile); + var packageXml = packagesXml.Root.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); + if (packageXml == null) return; + + packageXml.Remove(); + + packagesXml.Save(packagesFile); + } + + public bool SavePackage(PackageDefinition definition) { if (definition == null) throw new ArgumentNullException(nameof(definition)); var packagesXml = EnsureStorage(out var packagesFile); + //ensure it's valid + ValidatePackage(definition); + if (definition.Id == default) { //need to gen an id and persist // Find max id - var maxId = packagesXml.Root.Elements("package").Max(x => x.AttributeValue("id")); + var maxId = packagesXml.Root.Elements("package").Max(x => x.AttributeValue("id")) ?? 0; var newId = maxId + 1; definition.Id = newId; - definition.PackageGuid = Guid.NewGuid().ToString(); - definition.Folder = Guid.NewGuid().ToString(); + definition.PackageId = Guid.NewGuid(); + definition.FolderId = Guid.NewGuid(); var packageXml = PackageDefinitionToXml(definition); - packagesXml.Add(packageXml); + packagesXml.Root.Add(packageXml); } else { //existing var packageXml = packagesXml.Root.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == definition.Id); if (packageXml == null) - throw new InvalidOperationException($"The package with id {definition.Id} was not found"); + return false; var updatedXml = PackageDefinitionToXml(definition); packageXml.ReplaceWith(updatedXml); } packagesXml.Save(packagesFile); + + return true; } - public string ExportPackageDefinition(PackageDefinition definition) + public string ExportPackage(PackageDefinition definition) { if (definition.Id == default) throw new ArgumentException("The package definition does not have an ID, it must be saved before being exported"); - if (definition.PackageGuid.IsNullOrWhiteSpace()) throw new ArgumentException("the package definition does not have a GUID, it must be saved before being exported"); + if (definition.PackageId == default) throw new ArgumentException("the package definition does not have a GUID, it must be saved before being exported"); + if (definition.FolderId == default) throw new ArgumentException("the package definition does not have a folder GUID, it must be saved before being exported"); + + //ensure it's valid + ValidatePackage(definition); //Create a folder for building this package - var temporaryPath = IOHelper.MapPath(SystemDirectories.Data + "/TEMP/PackageFiles/" + definition.Folder); + var temporaryPath = IOHelper.MapPath(_tempFolderPath.EnsureEndsWith('/') + definition.FolderId); if (Directory.Exists(temporaryPath) == false) Directory.CreateDirectory(temporaryPath); @@ -90,7 +133,7 @@ namespace Umbraco.Core.Packaging var packageManifest = CreatePackageManifest(out var manifestRoot, out var filesXml); //Info section - packageManifest.Add(GetPackageInfoXml(definition)); + manifestRoot.Add(GetPackageInfoXml(definition)); PackageDocumentsAndTags(definition, manifestRoot); PackageDocumentTypes(definition, manifestRoot); @@ -124,7 +167,7 @@ namespace Umbraco.Core.Packaging } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); + _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); } } @@ -136,13 +179,17 @@ namespace Umbraco.Core.Packaging packageManifest.Save(manifestFileName); // check if there's a packages directory below media - var packagesDirectory = SystemDirectories.Media + "/created-packages"; - if (Directory.Exists(IOHelper.MapPath(packagesDirectory)) == false) - Directory.CreateDirectory(IOHelper.MapPath(packagesDirectory)); + + if (Directory.Exists(IOHelper.MapPath(_mediaFolderPath)) == false) + Directory.CreateDirectory(IOHelper.MapPath(_mediaFolderPath)); - var packPath = packagesDirectory + "/" + (definition.Name + "_" + definition.Version).Replace(' ', '_') + ".zip"; + var packPath = _mediaFolderPath.EnsureEndsWith('/') + (definition.Name + "_" + definition.Version).Replace(' ', '_') + ".zip"; ZipPackage(temporaryPath, IOHelper.MapPath(packPath)); + //we need to update the package path and save it + definition.PackagePath = packPath; + SavePackage(definition); + return packPath; } finally @@ -152,6 +199,16 @@ namespace Umbraco.Core.Packaging } } + private void ValidatePackage(PackageDefinition definition) + { + //ensure it's valid + var context = new ValidationContext(definition, serviceProvider: null, items: null); + var results = new List(); + var isValid = Validator.TryValidateObject(definition, context, results); + if (!isValid) + throw new InvalidOperationException("Validation failed, there is invalid data on the model: " + string.Join(", ", results.Select(x => x.ErrorMessage))); + } + private void PackageDataTypes(PackageDefinition definition, XContainer manifestRoot) { var dataTypes = new XElement("DataTypes"); @@ -342,6 +399,8 @@ namespace Umbraco.Core.Packaging /// The save path. private static void ZipPackage(string path, string savePath) { + if (File.Exists(savePath)) + File.Delete(savePath); ZipFile.CreateFromDirectory(path, savePath); } @@ -476,7 +535,7 @@ namespace Umbraco.Core.Packaging requirements.Add(new XElement("patch", definition.UmbracoVersion == null ? UmbracoVersion.SemanticVersion.Patch.ToInvariantString() : definition.UmbracoVersion.Build.ToInvariantString())); if (definition.UmbracoVersion != null) - requirements.Add(new XAttribute("type", "strict")); + requirements.Add(new XAttribute("type", RequirementsType.Strict.ToString())); package.Add(requirements); info.Add(package); @@ -496,13 +555,13 @@ namespace Umbraco.Core.Packaging { files = new XElement("files"); root = new XElement("umbPackage", files); - var packageManifest = new XDocument(); + var packageManifest = new XDocument(root); return packageManifest; } - private static XDocument EnsureStorage(out string packagesFile) + private XDocument EnsureStorage(out string packagesFile) { - var packagesFolder = IOHelper.MapPath(SystemDirectories.Packages); + var packagesFolder = IOHelper.MapPath(_packagesFolderPath); //ensure it exists Directory.CreateDirectory(packagesFolder); @@ -517,45 +576,80 @@ namespace Umbraco.Core.Packaging return packagesXml; } + private static PackageDefinition XmlToPackageDefinition(XElement xml) + { + if (xml == null) return null; + + var retVal = new PackageDefinition + { + Id = xml.AttributeValue("id"), + Name = xml.AttributeValue("name") ?? string.Empty, + FolderId = xml.AttributeValue("folder"), + PackagePath = xml.AttributeValue("packagePath") ?? string.Empty, + Version = xml.AttributeValue("version") ?? string.Empty, + Url = xml.AttributeValue("url") ?? string.Empty, + PackageId = xml.AttributeValue("packageGuid"), + IconUrl = xml.AttributeValue("iconUrl") ?? string.Empty, + UmbracoVersion = xml.AttributeValue("umbVersion"), + License = xml.Element("license")?.Value ?? string.Empty, + LicenseUrl = xml.Element("license")?.AttributeValue("url") ?? string.Empty, + Author = xml.Element("author")?.Value ?? string.Empty, + AuthorUrl = xml.Element("author")?.AttributeValue("url") ?? string.Empty, + Readme = xml.Element("readme")?.Value ?? string.Empty, + Actions = xml.Element("actions")?.ToString() ?? string.Empty, + ContentNodeId = xml.Element("content")?.AttributeValue("nodeId") ?? string.Empty, + ContentLoadChildNodes = xml.Element("content")?.AttributeValue("loadChildNodes") ?? false, + Macros = xml.Element("macros")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Templates = xml.Element("templates")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Stylesheets = xml.Element("stylesheets")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + DocumentTypes = xml.Element("documentTypes")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Languages = xml.Element("languages")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + DataTypes = xml.Element("datatypes")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Files = xml.Element("files")?.Elements("file").Select(x => x.Value).ToList() ?? new List(), + LoadControl = xml.Element("loadcontrol")?.Value ?? string.Empty + }; + + return retVal; + } + private static XElement PackageDefinitionToXml(PackageDefinition def) { var packageXml = new XElement("package", new XAttribute("id", def.Id), - new XAttribute("version", def.Version), - new XAttribute("url", def.Url), - new XAttribute("name", def.Name), - new XAttribute("folder", def.Folder), //fixme: What is this? - new XAttribute("packagepath", def.PackagePath), - new XAttribute("repositoryGuid", def.RepositoryGuid), - new XAttribute("iconUrl", def.IconUrl), + new XAttribute("version", def.Version ?? string.Empty), + new XAttribute("url", def.Url ?? string.Empty), + new XAttribute("name", def.Name ?? string.Empty), + new XAttribute("folder", def.FolderId), + new XAttribute("packagePath", def.PackagePath ?? string.Empty), + new XAttribute("iconUrl", def.IconUrl ?? string.Empty), new XAttribute("umbVersion", def.UmbracoVersion), - new XAttribute("packageGuid", def.PackageGuid), - new XAttribute("hasUpdate", def.HasUpdate), //fixme: What is this? + new XAttribute("packageGuid", def.PackageId), new XElement("license", - new XCData(def.License), - new XAttribute("url", def.LicenseUrl)), + new XCData(def.License ?? string.Empty), + new XAttribute("url", def.LicenseUrl ?? string.Empty)), new XElement("author", - new XCData(def.Author), - new XAttribute("url", def.AuthorUrl)), + new XCData(def.Author ?? string.Empty), + new XAttribute("url", def.AuthorUrl ?? string.Empty)), - new XElement("readme", def.Readme), - new XElement("actions", def.Actions), - new XElement("datatypes", string.Join(",", def.DataTypes)), + new XElement("readme", def.Readme ?? string.Empty), + new XElement("actions", def.Actions ?? string.Empty), + new XElement("datatypes", string.Join(",", def.DataTypes ?? Array.Empty())), new XElement("content", new XAttribute("nodeId", def.ContentNodeId), new XAttribute("loadChildNodes", def.ContentLoadChildNodes)), - new XElement("templates", string.Join(",", def.Templates)), - new XElement("stylesheets", string.Join(",", def.Stylesheets)), - new XElement("documentTypes", string.Join(",", def.DocumentTypes)), - new XElement("macros", string.Join(",", def.Macros)), - new XElement("files", string.Join(",", def.Files)), - new XElement("languages", string.Join(",", def.Languages)), - new XElement("dictionaryitems", string.Join(",", def.DictionaryItems)), - new XElement("loadcontrol", "")); //fixme: no more loadcontrol, needs to be an angular view + new XElement("templates", string.Join(",", def.Templates ?? Array.Empty())), + new XElement("stylesheets", string.Join(",", def.Stylesheets ?? Array.Empty())), + new XElement("documentTypes", string.Join(",", def.DocumentTypes ?? Array.Empty())), + new XElement("macros", string.Join(",", def.Macros ?? Array.Empty())), + new XElement("files", (def.Files ?? Array.Empty()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))), + new XElement("languages", string.Join(",", def.Languages ?? Array.Empty())), + new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty())), + new XElement("loadcontrol", def.LoadControl ?? string.Empty)); //fixme: no more loadcontrol, needs to be an angular view return packageXml; } diff --git a/src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs b/src/Umbraco.Core/Packaging/RequirementsType.cs similarity index 65% rename from src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs rename to src/Umbraco.Core/Packaging/RequirementsType.cs index ca91626128..38cac482c2 100644 --- a/src/Umbraco.Web/_Legacy/Packager/RequirementsType.cs +++ b/src/Umbraco.Core/Packaging/RequirementsType.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web._Legacy.Packager +namespace Umbraco.Core.Packaging { public enum RequirementsType { diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 585ea36aa9..4d60f3dca4 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -9,14 +9,27 @@ namespace Umbraco.Core.Services { public interface IPackagingService : IService { - #region Package Creation + #region Package Building + + IEnumerable GetAll(); + PackageDefinition GetById(int id); + void Delete(int id); + /// /// Persists a package definition to storage /// /// - void SavePackageDefinition(PackageDefinition definition); + bool SavePackage(PackageDefinition definition); + + /// + /// Creates the package file and returns it's physical path + /// + /// + string ExportPackage(PackageDefinition definition); + #endregion + #region Importing /// /// Imports and saves package xml as /// @@ -88,7 +101,8 @@ namespace Umbraco.Core.Services /// Optional id of the User performing the operation. Default is zero (admin) /// Optional parameter indicating whether or not to raise events /// An enumrable list of generated Templates - IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true); + IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true); + #endregion /// /// This will fetch an Umbraco package file from the package repository and return the relative file path to the downloaded package file diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 203a2cb2e8..17959f0983 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -46,7 +46,7 @@ namespace Umbraco.Core.Services.Implement private readonly IAuditRepository _auditRepository; private readonly IContentTypeRepository _contentTypeRepository; private readonly PropertyEditorCollection _propertyEditors; - private readonly IPackageCreation _packageCreation; + private readonly IPackageBuilder _packageBuilder; private static HttpClient _httpClient; public PackagingService( @@ -62,7 +62,7 @@ namespace Umbraco.Core.Services.Implement IAuditRepository auditRepository, IContentTypeRepository contentTypeRepository, PropertyEditorCollection propertyEditors, - IPackageCreation packageCreation) + IPackageBuilder packageBuilder) { _logger = logger; _contentService = contentService; @@ -76,7 +76,7 @@ namespace Umbraco.Core.Services.Implement _auditRepository = auditRepository; _contentTypeRepository = contentTypeRepository; _propertyEditors = propertyEditors; - _packageCreation = packageCreation; + _packageBuilder = packageBuilder; _importedContentTypes = new Dictionary(); } @@ -1402,7 +1402,15 @@ namespace Umbraco.Core.Services.Implement #region Package Building - public void SavePackageDefinition(PackageDefinition definition) => _packageCreation.SavePackageDefinition(definition); + public void Delete(int id) => _packageBuilder.Delete(id); + + public IEnumerable GetAll() => _packageBuilder.GetAll(); + + public PackageDefinition GetById(int id) => _packageBuilder.GetById(id); + + public bool SavePackage(PackageDefinition definition) => _packageBuilder.SavePackage(definition); + + public string ExportPackage(PackageDefinition definition) => _packageBuilder.ExportPackage(definition); #endregion diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 58ba136cc4..00179f562a 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -444,9 +444,10 @@ - + - + + diff --git a/src/Umbraco.Tests/Composing/TypeFinderTests.cs b/src/Umbraco.Tests/Composing/TypeFinderTests.cs index 2b9474310b..49c807b19f 100644 --- a/src/Umbraco.Tests/Composing/TypeFinderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeFinderTests.cs @@ -90,7 +90,7 @@ namespace Umbraco.Tests.Composing Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree] typesFound = TypeFinder.FindClassesWithAttribute(new[] { typeof (UmbracoContext).Assembly }); - Assert.AreEqual(21, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] + Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] } private static IProfilingLogger GetTestProfilingLogger() diff --git a/src/Umbraco.Tests/Services/PackagingServiceTests.cs b/src/Umbraco.Tests/Services/PackagingServiceTests.cs index a87e7907b5..2caf3e08b3 100644 --- a/src/Umbraco.Tests/Services/PackagingServiceTests.cs +++ b/src/Umbraco.Tests/Services/PackagingServiceTests.cs @@ -1,5 +1,4 @@ -using System; -using System.IO; +using System.IO; using NUnit.Framework; using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 120b0bcabb..c6602fc54e 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -170,7 +170,7 @@ namespace Umbraco.Tests.TestHelpers var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); var packagingService = GetLazyService(factory, c => new PackagingService( logger, contentService.Value, contentTypeService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, scopeProvider, GetRepo(c), GetRepo(c), new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())), - new PackageCreation(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new PackageBuilder(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger))); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 12b830407e..3e619c6f00 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -62,6 +62,8 @@ + + @@ -140,6 +142,7 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 0b74729cf6..ce2a557390 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -179,20 +179,29 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { 'Failed to get package'); }, + getEmpty: function () { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "getEmpty")), + 'Failed to get scaffold'); + }, + /** * @ngdoc method - * @name umbraco.resources.packageInstallResource#createPackage + * @name umbraco.resources.packageInstallResource#savePackage * @methodOf umbraco.resources.packageInstallResource * * @description - * Creates a new package + * Creates or updates a package */ - createPackage: function (umbPackage) { + savePackage: function (umbPackage) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( "packageApiBaseUrl", - "PostCreatePackage"), umbPackage), + "PostSavePackage"), umbPackage), 'Failed to create package'); }, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js index f3b64e0c28..b21909f573 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js @@ -119,6 +119,8 @@ function formHelper(angularHelper, serverValidationManager, notificationsService serverValidationManager.notifyAndClearAllSubscriptions(); } else { + + //TODO: All YSOD handling should be done with an interceptor overlayService.ysod(err); } } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index 0834799be4..fb1a1b8d5e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -177,6 +177,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe //show a ysod dialog if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { const error = { errorMsg: 'An error occured', data: response.data }; + //TODO: All YSOD handling should be done with an interceptor overlayService.ysod(error); } else { @@ -288,6 +289,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { //show a ysod dialog const error = { errorMsg: 'An error occured', data: response.data }; + //TODO: All YSOD handling should be done with an interceptor overlayService.ysod(error); } else { diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.delete.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.delete.controller.js index 92e02d0d14..e594bae2f4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.delete.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.delete.controller.js @@ -65,6 +65,7 @@ function ContentDeleteController($scope, $timeout, contentResource, treeService, //check if response is ysod if (err.status && err.status >= 500) { + //TODO: All YSOD handling should be done with an interceptor overlayService.ysod(err); } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/media/media.delete.controller.js b/src/Umbraco.Web.UI.Client/src/views/media/media.delete.controller.js index e5e95e94df..70b5120ebe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/media.delete.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/media/media.delete.controller.js @@ -59,6 +59,7 @@ function MediaDeleteController($scope, mediaResource, treeService, navigationSer //check if response is ysod if (err.status && err.status >= 500) { + //TODO: All YSOD handling should be done with an interceptor overlayService.ysod(err); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index f30c14816b..5f3832f79b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($scope, $location, $routeParams, entityResource, packageResource, contentTypeResource, templateResource, stylesheetResource, languageResource, dictionaryResource, dataTypeResource, editorService, formHelper) { + function EditController($scope, $location, $routeParams, entityResource, stylesheetResource, languageResource, packageResource, dictionaryResource, editorService, formHelper) { const vm = this; @@ -12,10 +12,9 @@ vm.contentOpen = true; vm.filesOpen = true; vm.actionsOpen = true; - + vm.loading = true; vm.back = back; - vm.createPackage = createPackage; - vm.save = save; + vm.createOrUpdatePackage = createOrUpdatePackage; vm.removeContentItem = removeContentItem; vm.openContentPicker = openContentPicker; vm.openFilePicker = openFilePicker; @@ -23,24 +22,23 @@ vm.openControlPicker = openControlPicker; vm.removeControl = removeControl; - function onInit() { + const packageId = $routeParams.id; + const create = $routeParams.create; - const packageId = $routeParams.id; - const create = $routeParams.create; + function onInit() { if(create) { //pre populate package with some values - vm.package = { - "version": "0.0.1", - "license": "MIT License", - "licenseUrl": "http://opensource.org/licenses/MIT", - "umbracoVersion": Umbraco.Sys.ServerVariables.application.version - }; + packageResource.getEmpty().then(scaffold => { + vm.package = scaffold; + vm.loading = false; + }); + vm.buttonLabel = "Create"; } else { // load package packageResource.getCreatedById(packageId).then(createdPackage => { vm.package = createdPackage; - + vm.loading = false; // get render model for content node if(vm.package.contentNodeId) { entityResource.getById(vm.package.contentNodeId, "Document") @@ -49,11 +47,12 @@ }); } - }, angular.noop); + }); + vm.buttonLabel = "Save"; } // get all doc types - contentTypeResource.getAll().then(documentTypes => { + entityResource.getAll("DocumentType").then(documentTypes => { // a package stores the id as a string so we // need to convert all ids to string for comparison documentTypes.forEach(documentType => { @@ -63,7 +62,7 @@ }); // get all templates - templateResource.getAll().then(templates => { + entityResource.getAll("Template").then(templates => { // a package stores the id as a string so we // need to convert all ids to string for comparison templates.forEach(template => { @@ -101,7 +100,7 @@ }); // get all data types items - dataTypeResource.getAll().then(dataTypes => { + entityResource.getAll("DataType").then(dataTypes => { // a package stores the id as a string so we // need to convert all ids to string for comparison dataTypes.forEach(dataType => { @@ -116,26 +115,31 @@ $location.path("packages/packages/overview").search('create', null);; } - function createPackage(editPackageForm) { + function createOrUpdatePackage(editPackageForm) { if (formHelper.submitForm({ formCtrl: editPackageForm, scope: $scope })) { - vm.createPackageButtonState = "busy"; + vm.buttonState = "busy"; + + packageResource.savePackage(vm.package).then((updatedPackage) => { - packageResource.createPackage(vm.package).then((updatedPackage) => { vm.package = updatedPackage; - vm.createPackageButtonState = "success"; + vm.buttonState = "success"; + + if (create) { + //if we are creating, then redirect to the correct url and reload + $location.path("packages/packages/overview/" + vm.package.id).search("subview", "created"); + //don't add a browser history for this + $location.replace(); + } + }, function(err){ formHelper.handleError(err); - vm.createPackageButtonState = "error"; + vm.buttonState = "error"; }); } } - function save() { - console.log("save package"); - } - function removeContentItem() { vm.package.contentNodeId = null; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index bf33c24d4d..b1a417fd6f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -300,14 +300,15 @@ - + + + @@ -316,4 +317,4 @@ -
\ No newline at end of file + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 9969cea687..9105b1170f 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -157,13 +157,6 @@ editMacro.aspx - - directoryBrowser.aspx - ASPXCodeBehind - - - directoryBrowser.aspx - default.Master ASPXCodeBehind @@ -209,7 +202,6 @@ - @@ -307,8 +299,6 @@ - - Designer diff --git a/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml b/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml index 0ebdb5cd48..635174b9da 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml @@ -15,32 +15,4 @@ - -
Package
- /create/simple.ascx - - - -
- -
Package
- /create/simple.ascx - - - -
- -
Package
- /create/simple.ascx - - - -
- -
Package
- /create/simple.ascx - - - -
diff --git a/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml b/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml index d6be62ff88..c075a0b8b9 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml @@ -15,32 +15,4 @@ - -
Package
- /create/simple.ascx - - - -
- -
Package
- /create/simple.ascx - - - -
- -
Package
- /create/simple.ascx - - - -
- -
Package
- /create/simple.ascx - - - -
diff --git a/src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.cs b/src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.cs deleted file mode 100644 index 3e2edd1471..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Web; -using System.Web.UI; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Web.UI.Pages; - -namespace Umbraco.Web.UI.Umbraco.Developer.Packages -{ - public partial class DirectoryBrowser : UmbracoEnsuredPage - { - public DirectoryBrowser() - { - CurrentApp = Constants.Applications.Packages; - } - - string _lsScriptName; - string _lsWebPath; - protected string Target = ""; - private readonly Regex _xssElementIdClean = new Regex(@"^([a-zA-Z0-9-_:\.]+)"); - - private readonly StringBuilder _sb = new StringBuilder(); - - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - - Response.Cache.SetExpires(DateTime.Now.AddSeconds(5)); - Response.Cache.SetCacheability(HttpCacheability.Public); - - //we need to clean this string: - //http://issues.umbraco.org/issue/U4-2027 - var target = Request.QueryString.Get("target"); - if (target.IsNullOrWhiteSpace()) - throw new InvalidOperationException("The target query string must be set to a valid html element id"); - var matched = _xssElementIdClean.Matches(target); - if (matched.Count == 0) - throw new InvalidOperationException("The target query string must be set to a valid html element id"); - - Target = matched[0].Value; - - try - { - - //Variables used in script - var sebChar = IOHelper.DirSepChar.ToString(); - - //Work on path and ensure no back tracking - string sSubDir = Request.QueryString.Get("path"); - if (string.IsNullOrEmpty(sSubDir)) { sSubDir = "/"; } - - sSubDir = sSubDir.Replace(IOHelper.DirSepChar.ToString(), ""); - sSubDir = sSubDir.Replace("//", "/"); - sSubDir = sSubDir.Replace("..", "./"); - sSubDir = sSubDir.Replace('/', IOHelper.DirSepChar); - - //Clean path for processing and collect path varitations - if (sSubDir.Substring(0, 1) != sebChar) { sSubDir = sebChar + sSubDir; } - if (sSubDir.Substring(sSubDir.Length - 1, 1) != "\\") { sSubDir = sSubDir + sebChar; } - - //Get name of the browser script file - _lsScriptName = Request.ServerVariables.Get("SCRIPT_NAME"); - var j = _lsScriptName.LastIndexOf("/"); - if (j > 0) { _lsScriptName = _lsScriptName.Substring(j + 1, _lsScriptName.Length - (j + 1)).ToLower(); } - - //Create navigation string and other path strings - GetNavLink("", "root"); - if (sSubDir != sebChar) - { - j = 0; int i = 0; - do - { - i = sSubDir.IndexOf(sebChar, j + 1); - _lsWebPath += sSubDir.Substring(j + 1, i - (j + 1)) + "/"; - GetNavLink(_lsWebPath, sSubDir.Substring(j + 1, i - (j + 1))); - j = i; - } while (i != sSubDir.Length - 1); - } - - //Output header - _sb.Append(""); - - //Output directorys - var oDirInfo = new DirectoryInfo(IOHelper.MapPath("~/" + sSubDir)); - var oDirs = oDirInfo.GetDirectories(); - foreach (var oDir in oDirs) - { - try - { - _sb.Append(""); - } - catch (Exception) - { - _sb.Append(""); - } - } - - //Ouput files - var oFiles = oDirInfo.GetFiles(); - foreach (var oFile in oFiles.Where(oFile => oFile.Name.ToLower() != _lsScriptName)) - { - decimal iLen = oFile.Length; - string sLen; - if (iLen >= 1048960) { iLen = iLen / 1048960; sLen = "mb"; } else { iLen = iLen / 1024; sLen = "kb"; } - sLen = Decimal.Round(iLen, 2).ToString() + sLen; - _sb.Append(""); - } - - //Output footer - _sb.Append("
" + oDir.Name + " (Include entire folder)
" + oDir.Name + " (Access Denied)
" + oFile.Name + "
"); - - } - catch (Exception ex) - { - RptErr(ex.Message); - } - } - - protected override void OnPreRender(EventArgs e) - { - base.OnPreRender(e); - Output.Controls.Add(new LiteralControl(_sb.ToString())); - } - - private void RptErr(string psMessage) - { - _sb.Append("
Script Reported Error:  " + psMessage + "

"); - } - - private string GetNavLink(string psHref, string psText) - { - return ("/" + psText + ""); - } - - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.designer.cs b/src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.designer.cs deleted file mode 100644 index 22bf0892b7..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/Packages/DirectoryBrowser.aspx.designer.cs +++ /dev/null @@ -1,42 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Umbraco.Web.UI.Umbraco.Developer.Packages { - - - public partial class DirectoryBrowser { - - /// - /// CssInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.CssInclude CssInclude1; - - /// - /// pane control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane pane; - - /// - /// Output control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder Output; - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/developer/Packages/directoryBrowser.aspx b/src/Umbraco.Web.UI/Umbraco/developer/Packages/directoryBrowser.aspx deleted file mode 100644 index c6d2645ab3..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/Packages/directoryBrowser.aspx +++ /dev/null @@ -1,26 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="True" MasterPageFile="../../masterpages/umbracoDialog.Master" CodeBehind="DirectoryBrowser.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.Developer.Packages.DirectoryBrowser" %> - -<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %> -<%@ Register TagPrefix="cdf" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> - - - - - - - - - - -
- - - -
-
diff --git a/src/Umbraco.Web.UI/Umbraco/developer/Packages/editPackage.aspx b/src/Umbraco.Web.UI/Umbraco/developer/Packages/editPackage.aspx deleted file mode 100644 index 956c17fe4a..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/Packages/editPackage.aspx +++ /dev/null @@ -1,232 +0,0 @@ -<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" MasterPageFile="../../masterpages/umbracoPage.Master" - Title="Package and export content" CodeBehind="editPackage.aspx.cs" Inherits="umbraco.presentation.developer.packages._Default" %> - -<%@ Register TagPrefix="cc2" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %> - - - - - - - - - * - - - - * - - - - * - - - - - - - - - - - - - - * - Invalid version number (eg. 7.5.0) - - - - - - - * - - - - * - - - - - - - * - - - - * - - - - - - - - - - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Remember: .ascx files for your macros - will be added automaticly, but you will still need to add assemblies, - images and script files manually to the list below. -
-
- - - - - - - - - - - - - - - - - -
- Absolute path to file (ie: /bin/umbraco.bin) - -
- - - -
- - - - - - -
-
- - - - - - - - -
- Load control after installation (ex: /usercontrols/installer.ascx) -
- - - - -
-
- - - - - - - - - - - -
-

- Here you can add custom installer / uninstaller events to perform certain tasks - during installation and uninstallation. -
- All actions are formed as a xml node, containing data for the action to be performed. - Package actions documentation -

- -
- Actions: -
- -
-
- -
diff --git a/src/Umbraco.Web.UI/Umbraco/developer/Packages/installer.aspx b/src/Umbraco.Web.UI/Umbraco/developer/Packages/installer.aspx deleted file mode 100644 index 1beda45dae..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/developer/Packages/installer.aspx +++ /dev/null @@ -1,10 +0,0 @@ -<%@ Page Language="c#" MasterPageFile="../../masterpages/umbracoPage.Master" -AutoEventWireup="True" Inherits="umbraco.presentation.developer.packages.Installer" Trace="false" ValidateRequest="false" %> -<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %> - - - - - - - diff --git a/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx b/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx deleted file mode 100644 index 956c17fe4a..0000000000 --- a/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx +++ /dev/null @@ -1,232 +0,0 @@ -<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" MasterPageFile="../../masterpages/umbracoPage.Master" - Title="Package and export content" CodeBehind="editPackage.aspx.cs" Inherits="umbraco.presentation.developer.packages._Default" %> - -<%@ Register TagPrefix="cc2" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %> - - - - - - - - - * - - - - * - - - - * - - - - - - - - - - - - - - * - Invalid version number (eg. 7.5.0) - - - - - - - * - - - - * - - - - - - - * - - - - * - - - - - - - - - - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Remember: .ascx files for your macros - will be added automaticly, but you will still need to add assemblies, - images and script files manually to the list below. -
-
- - - - - - - - - - - - - - - - - -
- Absolute path to file (ie: /bin/umbraco.bin) - -
- - - -
- - - - - - -
-
- - - - - - - - -
- Load control after installation (ex: /usercontrols/installer.ascx) -
- - - - -
-
- - - - - - - - - - - -
-

- Here you can add custom installer / uninstaller events to perform certain tasks - during installation and uninstallation. -
- All actions are formed as a xml node, containing data for the action to be performed. - Package actions documentation -

- -
- Actions: -
- -
-
- -
diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index dfb8823a39..66a0349417 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -23,57 +23,42 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageController : UmbracoAuthorizedJsonController { - public List GetCreatedPackages() + public IEnumerable GetCreatedPackages() { - return CreatedPackage.GetAllCreatedPackages().Select(x => x.Data).ToList(); + return Services.PackagingService.GetAll(); } public PackageDefinition GetCreatedPackageById(int id) { - var package = CreatedPackage.GetById(id); + var package = Services.PackagingService.GetById(id); if (package == null) throw new HttpResponseException(HttpStatusCode.NotFound); - return package.Data; + return package; } - public PackageDefinition PostUpdatePackage(PackageDefinition model) + public PackageDefinition GetEmpty() { - var package = CreatedPackage.GetById(model.Id); - if (package == null) - throw new HttpResponseException(HttpStatusCode.NotFound); - - if (ModelState.IsValid == false) - { - //Throw/bubble up errors - throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); - } - - package.Data = model; - - //We should have packagepath populated now - return package.Data; + return new PackageDefinition(); } - public PackageDefinition PostCreatePackage(PackageDefinition model) + /// + /// Creates or updates a package + /// + /// + /// + public PackageDefinition PostSavePackage(PackageDefinition model) { - //creating requires an empty model/package id - if (model.Id != 0 || model.PackageGuid != null) - throw new HttpResponseException(HttpStatusCode.NotFound); - if (ModelState.IsValid == false) - { - //Throw/bubble up errors throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); - } //save it - Services.PackagingService.SavePackageDefinition(model); + if (!Services.PackagingService.SavePackage(model)) + throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("The package with id {definition.Id} was not found")); - //then publish to get the file - //package.Publish(); - //TODO: We need a link to the downloadable zip file, in packagepath ? - + Services.PackagingService.ExportPackage(model); + + //the packagePath will be on the model return model; } @@ -86,11 +71,7 @@ namespace Umbraco.Web.Editors [HttpDelete] public IHttpActionResult DeleteCreatedPackage(int packageId) { - var package = CreatedPackage.GetById(packageId); - if (package == null) - return NotFound(); - - package.Delete(); + Services.PackagingService.Delete(packageId); return Ok(); } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index b58ed05bde..55e843aceb 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -510,7 +510,7 @@ namespace Umbraco.Web.Editors } model.TemporaryDirectoryPath = Path.Combine(SystemDirectories.Data, tempPath); - model.Id = ins.CreateManifest(IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid.ToString(), model.RepositoryGuid.ToString()); + model.Id = ins.CreateManifest(IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid, model.RepositoryGuid.ToString()); return model; } @@ -584,6 +584,7 @@ namespace Umbraco.Web.Editors var redirectUrl = ""; if (ins.Control.IsNullOrWhiteSpace() == false) { + //fixme: this needs to be replaced with an angular view the installer.aspx no longer exists. redirectUrl = string.Format("/developer/framed/{0}", Uri.EscapeDataString( string.Format("/umbraco/developer/Packages/installer.aspx?installing=custominstaller&dir={0}&pId={1}&customControl={2}&customUrl={3}", tempDir, model.Id, ins.Control, ins.Url))); diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs index 1fd2ac27bb..55680084e5 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs @@ -60,7 +60,7 @@ namespace Umbraco.Web.Install.Controllers var tempFile = installer.Import(packageFile); installer.LoadConfig(tempFile); - var pId = installer.CreateManifest(tempFile, model.KitGuid.ToString(), RepoGuid); + var pId = installer.CreateManifest(tempFile, model.KitGuid, RepoGuid); return Json(new { success = true, diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 8f9f9242d7..c79be96a93 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -68,7 +68,7 @@ namespace Umbraco.Web.Install.InstallSteps var tempFile = installer.Import(packageFile); installer.LoadConfig(tempFile); - var pId = installer.CreateManifest(tempFile, kitGuid.ToString(), RepoGuid); + var pId = installer.CreateManifest(tempFile, kitGuid, RepoGuid); InstallPackageFiles(pId, tempFile); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index fdf7f48201..b9a6c17ef7 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1142,10 +1142,7 @@ - - - @@ -1236,13 +1233,6 @@ FeedProxy.aspx - - editPackage.aspx - ASPXCodeBehind - - - editPackage.aspx - @@ -1288,9 +1278,6 @@ - - ASPXCodeBehind - diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 9d7fe77e7b..15a7839227 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -209,7 +209,7 @@ namespace Umbraco.Web._Legacy.Packager return Import(inputFile, true); } - public int CreateManifest(string tempDir, string guid, string repoGuid) + public int CreateManifest(string tempDir, Guid guid, string repoGuid) { //This is the new improved install rutine, which chops up the process into 3 steps, creating the manifest, moving files, and finally handling umb objects var packName = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name")); @@ -243,8 +243,7 @@ namespace Umbraco.Web._Legacy.Packager insPack.Data.Url = packUrl; insPack.Data.IconUrl = iconUrl; - insPack.Data.PackageGuid = guid; //the package unique key. - insPack.Data.RepositoryGuid = repoGuid; //the repository unique key, if the package is a file install, the repository will not get logged. + insPack.Data.PackageId = guid; //the package unique key. insPack.Save(); return insPack.Data.Id; @@ -324,7 +323,7 @@ namespace Umbraco.Web._Legacy.Packager { Current.Services.AuditService.Add(AuditType.PackagerInstall, _currentUserId, - -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Data.Name, insPack.Data.PackageGuid)); + -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Data.Name, insPack.Data.PackageId)); } insPack.Save(); @@ -373,7 +372,8 @@ namespace Umbraco.Web._Legacy.Packager if (languageItemsElement != null) { var insertedLanguages = packagingService.ImportLanguages(languageItemsElement); - insPack.Data.Languages.AddRange(insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))); + foreach(var x in insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))) + insPack.Data.Languages.Add(x); } #endregion @@ -383,7 +383,8 @@ namespace Umbraco.Web._Legacy.Packager if (dictionaryItemsElement != null) { var insertedDictionaryItems = packagingService.ImportDictionaryItems(dictionaryItemsElement); - insPack.Data.DictionaryItems.AddRange(insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))); + foreach (var x in insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))) + insPack.Data.DictionaryItems.Add(x); } #endregion @@ -392,7 +393,9 @@ namespace Umbraco.Web._Legacy.Packager if (macroItemsElement != null) { var insertedMacros = packagingService.ImportMacros(macroItemsElement); - insPack.Data.Macros.AddRange(insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))); + foreach (var x in insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))) + insPack.Data.Macros.Add(x); + } #endregion diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs deleted file mode 100644 index deff3b2ffd..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/CreatedPackage.cs +++ /dev/null @@ -1,387 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Xml; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.IO; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; -using File = System.IO.File; - - -namespace Umbraco.Web._Legacy.Packager.PackageInstance -{ - //TODO: Fix this class , service + model + internal? - public class CreatedPackage - { - - public static CreatedPackage GetById(int id) - { - var pack = new CreatedPackage(); - pack.Data = data.Package(id, IOHelper.MapPath(Settings.CreatedPackagesSettings)); - return pack; - } - - public static CreatedPackage MakeNew(string name, Core.Models.Packaging.PackageDefinition packageData = null) - { - var pack = new CreatedPackage - { - Data = packageData ?? data.MakeNew(name, IOHelper.MapPath(Settings.CreatedPackagesSettings)) - }; - - return pack; - } - - public void Save() - { - data.Save(this.Data, IOHelper.MapPath(Settings.CreatedPackagesSettings)); - } - - public void Delete() - { - data.Delete(this.Data.Id, IOHelper.MapPath(Settings.CreatedPackagesSettings)); - } - - public Core.Models.Packaging.PackageDefinition Data { get; set; } - - public static List GetAllCreatedPackages() - { - var val = new List(); - - foreach (var pack in data.GetAllPackages(IOHelper.MapPath(Settings.CreatedPackagesSettings))) - { - var crPack = new CreatedPackage(); - crPack.Data = pack; - val.Add(crPack); - } - - return val; - } - - private static XmlDocument _packageManifest; - private static void CreatePackageManifest() - { - _packageManifest = new XmlDocument(); - var xmldecl = _packageManifest.CreateXmlDeclaration("1.0", "UTF-8", "no"); - - _packageManifest.AppendChild(xmldecl); - - //root node - XmlNode umbPackage = _packageManifest.CreateElement("umbPackage"); - _packageManifest.AppendChild(umbPackage); - //Files node - umbPackage.AppendChild(_packageManifest.CreateElement("files")); - } - - private static void AppendElement(XmlNode node) - { - var root = _packageManifest.SelectSingleNode("/umbPackage"); - root.AppendChild(node); - } - - - public void Publish(IEntityXmlSerializer serializer) - { - - var package = this; - var pack = package.Data; - - var outInt = 0; - - //Path checking... - var localPath = IOHelper.MapPath(SystemDirectories.Media + "/" + pack.Folder); - - if (Directory.Exists(localPath) == false) - Directory.CreateDirectory(localPath); - - //Init package file... - CreatePackageManifest(); - //Info section.. - AppendElement(PackagerUtility.PackageInfo(pack, _packageManifest)); - - //Documents and tags... - var contentNodeId = 0; - if (string.IsNullOrEmpty(pack.ContentNodeId) == false && int.TryParse(pack.ContentNodeId, out contentNodeId)) - { - if (contentNodeId > 0) - { - //Create the Documents/DocumentSet node - XmlNode documents = _packageManifest.CreateElement("Documents"); - XmlNode documentSet = _packageManifest.CreateElement("DocumentSet"); - XmlAttribute importMode = _packageManifest.CreateAttribute("importMode", ""); - importMode.Value = "root"; - documentSet.Attributes.Append(importMode); - documents.AppendChild(documentSet); - - //load content from umbraco. - //var umbDocument = new Document(contentNodeId); - //var x = umbDocument.ToXml(_packageManifest, pack.ContentLoadChildNodes); - var udoc = Current.Services.ContentService.GetById(contentNodeId); - var xe = pack.ContentLoadChildNodes ? udoc.ToDeepXml(serializer) : udoc.ToXml(serializer); - var x = xe.GetXmlNode(_packageManifest); - documentSet.AppendChild(x); - - AppendElement(documents); - - ////Create the TagProperties node - this is used to store a definition for all - //// document properties that are tags, this ensures that we can re-import tags properly - //XmlNode tagProps = _packageManifest.CreateElement("TagProperties"); - - ////before we try to populate this, we'll do a quick lookup to see if any of the documents - //// being exported contain published tags. - //var allExportedIds = documents.SelectNodes("//@id").Cast() - // .Select(x => x.Value.TryConvertTo()) - // .Where(x => x.Success) - // .Select(x => x.Result) - // .ToArray(); - //var allContentTags = new List(); - //foreach (var exportedId in allExportedIds) - //{ - // allContentTags.AddRange( - // Current.Services.TagService.GetTagsForEntity(exportedId)); - //} - - ////This is pretty round-about but it works. Essentially we need to get the properties that are tagged - //// but to do that we need to lookup by a tag (string) - //var allTaggedEntities = new List(); - //foreach (var group in allContentTags.Select(x => x.Group).Distinct()) - //{ - // allTaggedEntities.AddRange( - // Current.Services.TagService.GetTaggedContentByTagGroup(group)); - //} - - ////Now, we have all property Ids/Aliases and their referenced document Ids and tags - //var allExportedTaggedEntities = allTaggedEntities.Where(x => allExportedIds.Contains(x.EntityId)) - // .DistinctBy(x => x.EntityId) - // .OrderBy(x => x.EntityId); - - //foreach (var taggedEntity in allExportedTaggedEntities) - //{ - // foreach (var taggedProperty in taggedEntity.TaggedProperties.Where(x => x.Tags.Any())) - // { - // XmlNode tagProp = _packageManifest.CreateElement("TagProperty"); - // var docId = _packageManifest.CreateAttribute("docId", ""); - // docId.Value = taggedEntity.EntityId.ToString(CultureInfo.InvariantCulture); - // tagProp.Attributes.Append(docId); - - // var propertyAlias = _packageManifest.CreateAttribute("propertyAlias", ""); - // propertyAlias.Value = taggedProperty.PropertyTypeAlias; - // tagProp.Attributes.Append(propertyAlias); - - // var group = _packageManifest.CreateAttribute("group", ""); - // group.Value = taggedProperty.Tags.First().Group; - // tagProp.Attributes.Append(group); - - // tagProp.AppendChild(_packageManifest.CreateCDataSection( - // JsonConvert.SerializeObject(taggedProperty.Tags.Select(x => x.Text).ToArray()))); - - // tagProps.AppendChild(tagProp); - // } - //} - - //AppendElement(tagProps); - - } - } - - //Document types.. - var dtl = new List(); - var docTypes = _packageManifest.CreateElement("DocumentTypes"); - foreach (var dtId in pack.DocumentTypes) - { - if (int.TryParse(dtId, out outInt)) - { - var docT = Current.Services.ContentTypeService.Get(outInt); - //DocumentType docT = new DocumentType(outInt); - - AddDocumentType(docT, ref dtl); - - } - } - - foreach (var d in dtl) - { - var xml = serializer.Serialize(d); - var xNode = xml.GetXmlNode(); - var n = (XmlElement) _packageManifest.ImportNode(xNode, true); - docTypes.AppendChild(n); - } - - AppendElement(docTypes); - - //Templates - var templates = _packageManifest.CreateElement("Templates"); - foreach (var templateId in pack.Templates) - { - if (int.TryParse(templateId, out outInt)) - { - var t = Current.Services.FileService.GetTemplate(outInt); - - var serialized = serializer.Serialize(t); - var n = serialized.GetXmlNode(_packageManifest); - - - templates.AppendChild(n); - } - } - AppendElement(templates); - - //Stylesheets - var stylesheets = _packageManifest.CreateElement("Stylesheets"); - foreach (var stylesheetName in pack.Stylesheets) - { - if (stylesheetName.IsNullOrWhiteSpace()) continue; - var stylesheetXmlNode = PackagerUtility.Stylesheet(stylesheetName, true, _packageManifest); - if (stylesheetXmlNode != null) - stylesheets.AppendChild(stylesheetXmlNode); - } - AppendElement(stylesheets); - - ////Macros - //var macros = _packageManifest.CreateElement("Macros"); - //foreach (var macroId in pack.Macros) - //{ - // if (int.TryParse(macroId, out outInt)) - // { - // macros.AppendChild(PackagerUtility.Macro(int.Parse(macroId), true, localPath, _packageManifest)); - // } - //} - //AppendElement(macros); - - //Dictionary Items - var dictionaryItems = _packageManifest.CreateElement("DictionaryItems"); - foreach (var dictionaryId in pack.DictionaryItems) - { - if (int.TryParse(dictionaryId, out outInt)) - { - var di = Current.Services.LocalizationService.GetDictionaryItemById(outInt); - var xmlNode = serializer.Serialize(di, false).GetXmlNode(_packageManifest); - dictionaryItems.AppendChild(xmlNode); - } - } - AppendElement(dictionaryItems); - - //Languages - var languages = _packageManifest.CreateElement("Languages"); - foreach (var langId in pack.Languages) - { - if (int.TryParse(langId, out outInt)) - { - var lang = Current.Services.LocalizationService.GetLanguageById(outInt); - - var xml = serializer.Serialize(lang); - var n = xml.GetXmlNode(_packageManifest); - - languages.AppendChild(n); - } - } - AppendElement(languages); - - //TODO: Fix this! ... actually once we use the new packager we don't need to - - ////Datatypes - //var dataTypes = _packageManifest.CreateElement("DataTypes"); - //foreach (var dtId in pack.DataTypes) - //{ - // if (int.TryParse(dtId, out outInt)) - // { - // datatype.DataTypeDefinition dtd = new datatype.DataTypeDefinition(outInt); - // dataTypes.AppendChild(dtd.ToXml(_packageManifest)); - // } - //} - //AppendElement(dataTypes); - - //Files - foreach (var fileName in pack.Files) - { - PackagerUtility.AppendFileToManifest(fileName, localPath, _packageManifest); - } - - //Load control on install... - if (string.IsNullOrEmpty(pack.LoadControl) == false) - { - XmlNode control = _packageManifest.CreateElement("control"); - control.InnerText = pack.LoadControl; - PackagerUtility.AppendFileToManifest(pack.LoadControl, localPath, _packageManifest); - AppendElement(control); - } - - //Actions - if (string.IsNullOrEmpty(pack.Actions) == false) - { - try - { - var xdActions = new XmlDocument(); - xdActions.LoadXml("" + pack.Actions + ""); - var actions = xdActions.DocumentElement.SelectSingleNode("."); - - - if (actions != null) - { - actions = _packageManifest.ImportNode(actions, true).Clone(); - AppendElement(actions); - } - } - catch - { - //TODO: Log!? - } - } - - var manifestFileName = localPath + "/package.xml"; - - if (File.Exists(manifestFileName)) - File.Delete(manifestFileName); - - _packageManifest.Save(manifestFileName); - _packageManifest = null; - - - //string packPath = Settings.PackagerRoot.Replace(System.IO.Path.DirectorySeparatorChar.ToString(), "/") + "/" + pack.Name.Replace(' ', '_') + "_" + pack.Version.Replace(' ', '_') + "." + Settings.PackageFileExtension; - - // check if there's a packages directory below media - var packagesDirectory = SystemDirectories.Media + "/created-packages"; - if (Directory.Exists(IOHelper.MapPath(packagesDirectory)) == false) - { - Directory.CreateDirectory(IOHelper.MapPath(packagesDirectory)); - } - - - var packPath = packagesDirectory + "/" + (pack.Name + "_" + pack.Version).Replace(' ', '_') + "." + Settings.PackageFileExtension; - PackagerUtility.ZipPackage(localPath, IOHelper.MapPath(packPath)); - - pack.PackagePath = packPath; - - if (pack.PackageGuid.Trim() == "") - pack.PackageGuid = Guid.NewGuid().ToString(); - - package.Save(); - - //Clean up.. - File.Delete(localPath + "/package.xml"); - Directory.Delete(localPath, true); - } - - private void AddDocumentType(IContentType dt, ref List dtl) - { - if (dt.ParentId > 0) - { - var parent = Current.Services.ContentTypeService.Get(dt.ParentId); - if (parent != null) // could be a container - { - AddDocumentType(parent, ref dtl); - } - } - - if (dtl.Contains(dt) == false) - { - dtl.Add(dt); - } - } - - - - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs index 8c106f142d..d7ea239a3f 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs @@ -72,7 +72,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance public void Delete(int userId) { - Current.Services.AuditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", string.Format("Package '{0}' uninstalled. Package guid: {1}", Data.Name, Data.PackageGuid)); + Current.Services.AuditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", string.Format("Package '{0}' uninstalled. Package guid: {1}", Data.Name, Data.PackageId)); Delete(); } diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs deleted file mode 100644 index af32e8c80a..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/PackagerUtility.cs +++ /dev/null @@ -1,279 +0,0 @@ -using System; -using System.Collections; -using System.IO; -using System.Xml; -using ICSharpCode.SharpZipLib.Zip; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.IO; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; - -namespace Umbraco.Web._Legacy.Packager.PackageInstance -{ - /// - /// A utillity class for working with packager data. - /// It provides basic methods for adding new items to a package manifest, moving files and other misc. - /// - public class PackagerUtility - { - /// - /// Creates a package manifest containing name, license, version and other meta data. - /// - /// The packinstance. - /// The xml document. - /// - public static XmlNode PackageInfo(Core.Models.Packaging.PackageDefinition pack, XmlDocument doc) - { - XmlNode info = doc.CreateElement("info"); - - //Package info - XmlNode package = doc.CreateElement("package"); - package.AppendChild(CreateNode("name", pack.Name, doc)); - package.AppendChild(CreateNode("version", pack.Version, doc)); - package.AppendChild(CreateNode("iconUrl", pack.IconUrl, doc)); - - XmlNode license = CreateNode("license", pack.License, doc); - license.Attributes.Append(CreateAttribute("url", pack.LicenseUrl, doc)); - package.AppendChild(license); - - package.AppendChild(CreateNode("url", pack.Url, doc)); - - XmlNode requirements = doc.CreateElement("requirements"); - //NOTE: The defaults are 3.0.0 - I'm just leaving that here since that's the way it's been //SD - requirements.AppendChild(CreateNode("major", pack.UmbracoVersion == null ? "3" : pack.UmbracoVersion.Major.ToInvariantString(), doc)); - requirements.AppendChild(CreateNode("minor", pack.UmbracoVersion == null ? "0" : pack.UmbracoVersion.Minor.ToInvariantString(), doc)); - requirements.AppendChild(CreateNode("patch", pack.UmbracoVersion == null ? "0" : pack.UmbracoVersion.Build.ToInvariantString(), doc)); - if (pack.UmbracoVersion != null) - requirements.Attributes.Append(CreateAttribute("type", "strict", doc)); - - package.AppendChild(requirements); - info.AppendChild(package); - - //Author - XmlNode author = CreateNode("author", "", doc); - author.AppendChild(CreateNode("name", pack.Author, doc)); - author.AppendChild(CreateNode("website", pack.AuthorUrl, doc)); - info.AppendChild(author); - - info.AppendChild(CreateNode("readme", "", doc)); - - return info; - } - - /// - /// Converts a umbraco stylesheet to a package xml node - /// - /// The name of the stylesheet. - /// if set to true [incluce properties]. - /// The doc. - /// - public static XmlNode Stylesheet(string name, bool includeProperties, XmlDocument doc) - { - if (doc == null) throw new ArgumentNullException("doc"); - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name"); - - var fileService = Current.Services.FileService; - var sts = fileService.GetStylesheetByName(name); - var stylesheet = doc.CreateElement("Stylesheet"); - stylesheet.AppendChild(CreateNode("Name", sts.Alias, doc)); - stylesheet.AppendChild(CreateNode("FileName", sts.Name, doc)); - stylesheet.AppendChild(CreateNode("Content", "", doc)); - if (includeProperties) - { - var properties = doc.CreateElement("Properties"); - foreach (var ssP in sts.Properties) - { - var property = doc.CreateElement("Property"); - property.AppendChild(CreateNode("Name", ssP.Name, doc)); - property.AppendChild(CreateNode("Alias", ssP.Alias, doc)); - property.AppendChild(CreateNode("Value", ssP.Value, doc)); - } - stylesheet.AppendChild(properties); - } - return stylesheet; - } - - - /// - /// Appends a file to package manifest and copies the file to the correct folder. - /// - /// The path. - /// The package directory. - /// The doc. - public static void AppendFileToManifest(string path, string packageDirectory, XmlDocument doc) - { - if (!path.StartsWith("~/") && !path.StartsWith("/")) - path = "~/" + path; - - string serverPath = IOHelper.MapPath(path); - - if (System.IO.File.Exists(serverPath)) - - AppendFileXml(path, packageDirectory, doc); - else if (System.IO.Directory.Exists(serverPath)) - ProcessDirectory(path, packageDirectory, doc); - } - - - - //Process files in directory and add them to package - private static void ProcessDirectory(string path, string packageDirectory, XmlDocument doc) - { - string serverPath = IOHelper.MapPath(path); - if (System.IO.Directory.Exists(serverPath)) - { - System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(serverPath); - - foreach (System.IO.FileInfo file in di.GetFiles()) - AppendFileXml(path + "/" + file.Name, packageDirectory, doc); - - foreach (System.IO.DirectoryInfo dir in di.GetDirectories()) - ProcessDirectory(path + "/" + dir.Name, packageDirectory, doc); - } - } - - private static void AppendFileXml(string path, string packageDirectory, XmlDocument doc) - { - - string serverPath = IOHelper.MapPath(path); - - string orgPath = path.Substring(0, (path.LastIndexOf('/'))); - string orgName = path.Substring((path.LastIndexOf('/') + 1)); - string newFileName = orgName; - - if (System.IO.File.Exists(packageDirectory + "/" + orgName)) - { - string fileGuid = System.Guid.NewGuid().ToString(); - newFileName = fileGuid + "_" + newFileName; - } - - //Copy file to directory for zipping... - System.IO.File.Copy(serverPath, packageDirectory + "/" + newFileName, true); - - //Append file info to files xml node - XmlNode files = doc.SelectSingleNode("/umbPackage/files"); - - XmlNode file = doc.CreateElement("file"); - file.AppendChild(CreateNode("guid", newFileName, doc)); - file.AppendChild(CreateNode("orgPath", orgPath == "" ? "/" : orgPath, doc)); - file.AppendChild(CreateNode("orgName", orgName, doc)); - - files.AppendChild(file); - } - - /// - /// Determines whether the file is in the package manifest - /// - /// The GUID. - /// The doc. - /// - /// true if [is file in manifest]; otherwise, false. - /// - public static bool IsFileInManifest(string guid, XmlDocument doc) - { - return false; - } - - private static XmlNode CreateNode(string name, string value, XmlDocument doc) - { - var node = doc.CreateElement(name); - node.InnerXml = value; - return node; - } - - private static XmlAttribute CreateAttribute(string name, string value, XmlDocument doc) - { - var attribute = doc.CreateAttribute(name); - attribute.Value = value; - return attribute; - } - - /// - /// Zips the package. - /// - /// The path. - /// The save path. - public static void ZipPackage(string Path, string savePath) - { - string OutPath = savePath; - - ArrayList ar = GenerateFileList(Path); - // generate file list - // find number of chars to remove from orginal file path - int TrimLength = (Directory.GetParent(Path)).ToString().Length; - - TrimLength += 1; - - //remove '\' - FileStream ostream; - - byte[] obuffer; - - ZipOutputStream oZipStream = new ZipOutputStream(System.IO.File.Create(OutPath)); - // create zip stream - - - oZipStream.SetLevel(9); - // 9 = maximum compression level - ZipEntry oZipEntry; - - foreach (string Fil in ar) // for each file, generate a zipentry - { - oZipEntry = new ZipEntry(Fil.Remove(0, TrimLength)); - oZipStream.PutNextEntry(oZipEntry); - - - if (!Fil.EndsWith(@"/")) // if a file ends with '/' its a directory - { - ostream = File.OpenRead(Fil); - - obuffer = new byte[ostream.Length]; - - // byte buffer - ostream.Read(obuffer, 0, obuffer.Length); - - oZipStream.Write(obuffer, 0, obuffer.Length); - ostream.Close(); - } - } - oZipStream.Finish(); - oZipStream.Close(); - oZipStream.Dispose(); - oZipStream = null; - - oZipEntry = null; - - - ostream = null; - ar.Clear(); - ar = null; - } - - private static ArrayList GenerateFileList(string Dir) - { - ArrayList mid = new ArrayList(); - - bool Empty = true; - - // add each file in directory - foreach (string file in Directory.GetFiles(Dir)) - { - mid.Add(file); - Empty = false; - } - - // if directory is completely empty, add it - if (Empty && Directory.GetDirectories(Dir).Length == 0) - mid.Add(Dir + @"/"); - - // do this recursively - foreach (string dirs in Directory.GetDirectories(Dir)) - { - foreach (object obj in GenerateFileList(dirs)) - mid.Add(obj); - } - return mid; // return file list - } - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/Settings.cs b/src/Umbraco.Web/_Legacy/Packager/Settings.cs index 92b0ae030a..e88f18262f 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Settings.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Settings.cs @@ -8,10 +8,6 @@ namespace Umbraco.Web._Legacy.Packager { public static string InstalledPackagesSettings => SystemDirectories.Packages + IOHelper.DirSepChar + "installedPackages.config"; - public static string CreatedPackagesSettings => SystemDirectories.Packages + IOHelper.DirSepChar + "createdPackages.config"; - - public static string PackageFileExtension => "zip"; - } } diff --git a/src/Umbraco.Web/_Legacy/Packager/data.cs b/src/Umbraco.Web/_Legacy/Packager/data.cs index 1882c151d2..51f0799689 100644 --- a/src/Umbraco.Web/_Legacy/Packager/data.cs +++ b/src/Umbraco.Web/_Legacy/Packager/data.cs @@ -95,7 +95,7 @@ namespace Umbraco.Web._Legacy.Packager instance.Attributes.Append(XmlHelper.AddAttribute(Source, "url", "")); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "name", name)); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "folder", Guid.NewGuid().ToString())); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "packagepath", "")); + instance.Attributes.Append(XmlHelper.AddAttribute(Source, "packagePath", "")); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "repositoryGuid", "")); instance.Attributes.Append(XmlHelper.AddAttribute(Source, "iconUrl", "")); //set to current version @@ -187,13 +187,11 @@ namespace Umbraco.Web._Legacy.Packager { retVal.Id = int.Parse(SafeAttribute("id", n)); retVal.Name = SafeAttribute("name", n); - retVal.Folder = SafeAttribute("folder", n); - retVal.PackagePath = SafeAttribute("packagepath", n); + retVal.FolderId = Guid.Parse(SafeAttribute("folder", n)); + retVal.PackagePath = SafeAttribute("packagePath", n); retVal.Version = SafeAttribute("version", n); retVal.Url = SafeAttribute("url", n); - retVal.RepositoryGuid = SafeAttribute("repositoryGuid", n); - retVal.PackageGuid = SafeAttribute("packageGuid", n); - retVal.HasUpdate = bool.Parse(SafeAttribute("hasUpdate", n)); + retVal.PackageId = Guid.Parse(SafeAttribute("packageGuid", n)); retVal.IconUrl = SafeAttribute("iconUrl", n); var umbVersion = SafeAttribute("umbVersion", n); @@ -262,10 +260,8 @@ namespace Umbraco.Web._Legacy.Packager XmlHelper.SetAttribute(Source, xmlDef, "name", package.Name); XmlHelper.SetAttribute(Source, xmlDef, "version", package.Version); XmlHelper.SetAttribute(Source, xmlDef, "url", package.Url); - XmlHelper.SetAttribute(Source, xmlDef, "packagepath", package.PackagePath); - XmlHelper.SetAttribute(Source, xmlDef, "repositoryGuid", package.RepositoryGuid); - XmlHelper.SetAttribute(Source, xmlDef, "packageGuid", package.PackageGuid); - XmlHelper.SetAttribute(Source, xmlDef, "hasUpdate", package.HasUpdate.ToString()); + XmlHelper.SetAttribute(Source, xmlDef, "packagePath", package.PackagePath); + XmlHelper.SetAttribute(Source, xmlDef, "packageGuid", package.PackageId.ToString()); XmlHelper.SetAttribute(Source, xmlDef, "iconUrl", package.IconUrl); if (package.UmbracoVersion != null) XmlHelper.SetAttribute(Source, xmlDef, "umbVersion", package.UmbracoVersion.ToString(3)); @@ -359,7 +355,7 @@ namespace Umbraco.Web._Legacy.Packager } - private static string JoinList(List list, char seperator) + private static string JoinList(IList list, char seperator) { string retVal = ""; foreach (string str in list) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx deleted file mode 100644 index d7b71ecde1..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx +++ /dev/null @@ -1,232 +0,0 @@ -<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" MasterPageFile="../../masterpages/umbracoPage.Master" - Title="Package and export content" CodeBehind="editPackage.aspx.cs" Inherits="umbraco.presentation.developer.packages._Default" %> - -<%@ Register TagPrefix="cc2" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %> - - - - - - - - - * - - - - * - - - - * - - - - - - - - - - - - - - * - Invalid version number (eg. 7.5.0) - - - - - - - * - - - - * - - - - - - - * - - - - * - - - - - - - - - - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Remember: .xslt and .ascx files for your macros - will be added automaticly, but you will still need to add assemblies, - images and script files manually to the list below. -
-
- - - - - - - - - - - - - - - - - -
- Absolute path to file (ie: /bin/umbraco.bin) - -
- - - -
- - - - - - -
-
- - - - - - - - -
- Load control after installation (ex: /usercontrols/installer.ascx) -
- - - - -
-
- - - - - - - - - - - -
-

- Here you can add custom installer / uninstaller events to perform certain tasks - during installation and uninstallation. -
- All actions are formed as a xml node, containing data for the action to be performed. - Package actions documentation -

- -
- Actions: -
- -
-
- -
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs deleted file mode 100644 index 3b863895a4..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs +++ /dev/null @@ -1,453 +0,0 @@ -using Umbraco.Core.Services; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Web.UI; -using System.Web.UI.WebControls; - -using System.Xml; -using umbraco.controls; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Models.Packaging; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.UI; -using Umbraco.Web.UI.Pages; -using Umbraco.Web._Legacy.Packager.PackageInstance; - -namespace umbraco.presentation.developer.packages -{ - public partial class _Default : UmbracoEnsuredPage - { - - public _Default() - { - CurrentApp = Constants.Applications.Packages.ToString(); - - } - public Umbraco.Web._Legacy.Controls.TabPage packageInfo; - public Umbraco.Web._Legacy.Controls.TabPage packageContents; - public Umbraco.Web._Legacy.Controls.TabPage packageFiles; - public Umbraco.Web._Legacy.Controls.TabPage packageOutput; - public Umbraco.Web._Legacy.Controls.TabPage packageAbout; - public Umbraco.Web._Legacy.Controls.TabPage packageActions; - - protected ContentPicker cp; - private PackageDefinition pack; - private CreatedPackage createdPackage; - - protected void Page_Load(object sender, EventArgs e) - { - if (Request.QueryString["id"] != null) - { - createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - pack = createdPackage.Data; - - /* CONTENT */ - - cp = new ContentPicker(); - content.Controls.Add(cp); - - if (string.IsNullOrEmpty(pack.PackagePath) == false) - { - packageUmbFile.Text = "   Download"; - } - else - { - packageUmbFile.Text = "This package is not published"; - } - - if (Page.IsPostBack == false) - { - ClientTools - .SyncTree("-1,created," + createdPackage.Data.Id, false); - - packageAuthorName.Text = pack.Author; - packageAuthorUrl.Text = pack.AuthorUrl; - packageLicenseName.Text = pack.License; - packageLicenseUrl.Text = pack.LicenseUrl; - packageName.Text = pack.Name; - packageReadme.Text = pack.Readme; - packageVersion.Text = pack.Version; - packageUrl.Text = pack.Url; - iconUrl.Text = pack.IconUrl; - umbracoVersion.Text = pack.UmbracoVersion != null ? pack.UmbracoVersion.ToString(3) : string.Empty; - - /*ACTIONS XML*/ - tb_actions.Text = pack.Actions; - - cp.Value = pack.ContentNodeId.ToString(); - - //startNode.Value = pack.ContentNodeId.ToString(); - - packageContentSubdirs.Checked = pack.ContentLoadChildNodes; - - - /*TEMPLATES */ - var nTemplates = Services.FileService.GetTemplates(); - //Template[] umbTemplates = Template.GetAllAsList().ToArray(); - foreach (var tmp in nTemplates) - { - ListItem li = new ListItem(tmp.Name, tmp.Id.ToString()); - - if (pack.Templates.Contains(tmp.Id.ToString())) - li.Selected = true; - - templates.Items.Add(li); - } - - /* DOC TYPES */ - // fixme - media types? member types? - var nContentTypes = Services.ContentTypeService.GetAll(); - //DocumentType[] docs = DocumentType.GetAllAsList().ToArray(); - foreach (var dc in nContentTypes) - { - ListItem li = new ListItem(dc.Name, dc.Id.ToString()); - if (pack.DocumentTypes.Contains(dc.Id.ToString())) - li.Selected = true; - - documentTypes.Items.Add(li); - } - - /*Stylesheets */ - var sheets = Services.FileService.GetStylesheets(); - foreach (var st in sheets) - { - if (string.IsNullOrEmpty(st.Name) == false) - { - var li = new ListItem(st.Alias, st.Name); - if (pack.Stylesheets.Contains(st.Name)) - li.Selected = true; - stylesheets.Items.Add(li); - } - } - - /* MACROS */ - var nMacros = Services.MacroService.GetAll(); - //Macro[] umbMacros = Macro.GetAll(); - foreach (var m in nMacros) - { - ListItem li = new ListItem(m.Name, m.Id.ToString()); - if (pack.Macros.Contains(m.Id.ToString())) - li.Selected = true; - - macros.Items.Add(li); - } - - /*Langauges */ - var nLanguages = Services.LocalizationService.GetAllLanguages(); - //Language[] umbLanguages = Language.getAll; - foreach (var l in nLanguages) - { - ListItem li = new ListItem(l.CultureName, l.Id.ToString()); - if (pack.Languages.Contains(l.Id.ToString())) - li.Selected = true; - - languages.Items.Add(li); - } - - /*Dictionary Items*/ - var umbDictionary = Services.LocalizationService.GetRootDictionaryItems(); - foreach (var d in umbDictionary) - { - - string liName = d.ItemKey; - var children = Services.LocalizationService.GetDictionaryItemChildren(d.Key); - if (children.Any()) - liName += " (Including all child items)"; - - var li = new ListItem(liName, d.Id.ToString()); - - if (pack.DictionaryItems.Contains(d.Id.ToString())) - li.Selected = true; - - dictionary.Items.Add(li); - } - - //TODO: Fix this with the new services and apis! and then remove since this should all be in angular - - ///*Data types */ - //cms.businesslogic.datatype.DataTypeDefinition[] umbDataType = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); - - // sort array by name - //Array.Sort(umbDataType, delegate(cms.businesslogic.datatype.DataTypeDefinition umbDataType1, cms.businesslogic.datatype.DataTypeDefinition umbDataType2) - //{ - // return umbDataType1.Text.CompareTo(umbDataType2.Text); - //}); - - //foreach (cms.businesslogic.datatype.DataTypeDefinition umbDtd in umbDataType) - //{ - - // ListItem li = new ListItem(umbDtd.Text, umbDtd.Id.ToString()); - - // if (pack.DataTypes.Contains(umbDtd.Id.ToString())) - // li.Selected = true; - - // cbl_datatypes.Items.Add(li); - //} - - /* FILES */ - packageFilesRepeater.DataSource = pack.Files; - packageFilesRepeater.DataBind(); - - packageControlPath.Text = pack.LoadControl; - } - else - { - ClientTools - .SyncTree("-1,created," + createdPackage.Data.Id, true); - } - } - } - - protected void validateActions(object sender, ServerValidateEventArgs e) - { - string actions = tb_actions.Text; - if (!string.IsNullOrEmpty(actions)) - { - - actions = "" + actions + ""; - - try - { - //we try to load an xml document with the potential malformed xml to ensure that this is actual action xml... - XmlDocument xd = new XmlDocument(); - xd.LoadXml(actions); - e.IsValid = true; - } - catch - { - e.IsValid = false; - } - } - else - e.IsValid = true; - } - - //protected void saveOrPublish(object sender, CommandEventArgs e) - //{ - - // if (!Page.IsValid) - // { - // this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, "Saved failed.", "Some fields have not been filled-out correctly"); - // } - // else - // { - // if (e.CommandName == "save") - // SavePackage(true); - - // if (e.CommandName == "publish") - // { - // SavePackage(false); - // int packageID = int.Parse(Request.QueryString["id"]); - // //string packFileName = cms.businesslogic.packager. Publish.publishPackage(packageID); - - // createdPackage.Publish(); - - - // if (!string.IsNullOrEmpty(pack.PackagePath)) - // { - - // packageUmbFile.Text = "   Download"; - - // this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Success, "Package saved and published", ""); - // } - // else - // { - // this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, "Save failed", "check your umbraco log."); - // } - // } - // } - //} - - - private void SavePackage(bool showNotification) - { - pack.Author = packageAuthorName.Text; - pack.AuthorUrl = packageAuthorUrl.Text; - - pack.License = packageLicenseName.Text; - pack.LicenseUrl = packageLicenseUrl.Text; - - pack.Readme = packageReadme.Text; - pack.Actions = tb_actions.Text; - - pack.Name = packageName.Text; - pack.Url = packageUrl.Text; - pack.Version = packageVersion.Text; - pack.IconUrl = iconUrl.Text; - pack.UmbracoVersion = Version.Parse(umbracoVersion.Text); - - pack.ContentLoadChildNodes = packageContentSubdirs.Checked; - - if (string.IsNullOrEmpty(cp.Value) == false) - pack.ContentNodeId = cp.Value; - else - pack.ContentNodeId = ""; - - - string tmpStylesheets = ""; - foreach (ListItem li in stylesheets.Items) - { - if (li.Selected) - tmpStylesheets += li.Value + ","; - } - pack.Stylesheets = new List(tmpStylesheets.Trim(',').Split(',')); - - - string tmpDoctypes = ""; - foreach (ListItem li in documentTypes.Items) - { - if (li.Selected) - tmpDoctypes += li.Value + ","; - } - pack.DocumentTypes = new List(tmpDoctypes.Trim(',').Split(',')); - - - string tmpMacros = ""; - foreach (ListItem li in macros.Items) - { - if (li.Selected) - tmpMacros += li.Value + ","; - } - pack.Macros = new List(tmpMacros.Trim(',').Split(',')); - - - string tmpLanguages = ""; - foreach (ListItem li in languages.Items) - { - if (li.Selected) - tmpLanguages += li.Value + ","; - } - pack.Languages = new List(tmpLanguages.Trim(',').Split(',')); - - string tmpDictionaries = ""; - foreach (ListItem li in dictionary.Items) - { - if (li.Selected) - tmpDictionaries += li.Value + ","; - } - pack.DictionaryItems = new List(tmpDictionaries.Trim(',').Split(',')); - - - string tmpTemplates = ""; - foreach (ListItem li in templates.Items) - { - if (li.Selected) - tmpTemplates += li.Value + ","; - } - pack.Templates = new List(tmpTemplates.Trim(',').Split(',')); - - string tmpDataTypes = ""; - foreach (ListItem li in cbl_datatypes.Items) - { - if (li.Selected) - tmpDataTypes += li.Value + ","; - } - pack.DataTypes = new List(tmpDataTypes.Trim(',').Split(',')); - - pack.LoadControl = packageControlPath.Text; - - - createdPackage.Save(); - - if (showNotification) - this.ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Save, "Package Saved", ""); - } - - protected void addFileToPackage(object sender, EventArgs e) - { - string newPath = packageFilePathNew.Text; - - if (newPath.Trim() != "") - { - CreatedPackage createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - PackageDefinition pack = createdPackage.Data; - - pack.Files.Add(newPath); - - createdPackage.Save(); - - packageFilePathNew.Text = ""; - - packageFilesRepeater.DataSource = pack.Files; - packageFilesRepeater.DataBind(); - } - } - - protected void deleteFileFromPackage(object sender, EventArgs e) - { - TextBox filePathControl = (TextBox)((Control)sender).Parent.FindControl("packageFilePath"); - filePathControl.Text = ""; - - string tmpFilePathString = ""; - foreach (RepeaterItem rItem in packageFilesRepeater.Items) - { - string tmpFFFF = ((TextBox)rItem.FindControl("packageFilePath")).Text; - if (tmpFFFF.Trim() != "") - tmpFilePathString += tmpFFFF + "�"; - } - - CreatedPackage createdPackage = CreatedPackage.GetById(int.Parse(Request.QueryString["id"])); - PackageDefinition pack = createdPackage.Data; - - pack.Files = new List(tmpFilePathString.Trim('�').Split('�')); - pack.Files.TrimExcess(); - - createdPackage.Save(); - - packageFilesRepeater.DataSource = pack.Files; - packageFilesRepeater.DataBind(); - } - - protected override void OnInit(EventArgs e) - { - // Tab setup - packageInfo = TabView1.NewTabPage("Package Properties"); - packageInfo.Controls.Add(Pane1); - packageInfo.Controls.Add(Pane5); - packageInfo.Controls.Add(Pane1_1); - packageInfo.Controls.Add(Pane1_2); - packageInfo.Controls.Add(Pane1_3); - - - packageContents = TabView1.NewTabPage("Package Contents"); - packageContents.Controls.Add(Pane2); - packageContents.Controls.Add(Pane2_1); - packageContents.Controls.Add(Pane2_2); - packageContents.Controls.Add(Pane2_3); - packageContents.Controls.Add(Pane2_4); - packageContents.Controls.Add(Pane2_5); - packageContents.Controls.Add(Pane2_6); - packageContents.Controls.Add(Pane2_7); - - packageFiles = TabView1.NewTabPage("Package Files"); - packageFiles.Controls.Add(Pane3); - packageFiles.Controls.Add(Pane3_1); - packageFiles.Controls.Add(Pane3_2); - - packageActions = TabView1.NewTabPage("Package Actions"); - packageActions.Controls.Add(Pane4); - - //var pubs = TabView1.Menu.NewButton(); - //pubs.Text = Services.TextService.Localize("publish"); - //pubs.CommandName = "publish"; - //pubs.Command += new CommandEventHandler(saveOrPublish); - //pubs.ID = "saveAndPublish"; - - //var saves = TabView1.Menu.NewButton(); - //saves.Text = Services.TextService.Localize("save"); - //saves.CommandName = "save"; - //saves.Command += new CommandEventHandler(saveOrPublish); - //saves.ButtonType = Umbraco.Web._Legacy.Controls.MenuButtonType.Primary; - //saves.ID = "save"; - - - - - base.OnInit(e); - } - - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.designer.cs deleted file mode 100644 index d41967444a..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.designer.cs +++ /dev/null @@ -1,609 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace umbraco.presentation.developer.packages { - - - public partial class _Default { - - /// - /// TabView1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.TabView TabView1; - - /// - /// Pane1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane1; - - /// - /// pp_name control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_name; - - /// - /// packageName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageName; - - /// - /// RequiredFieldValidator0 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator0; - - /// - /// pp_url control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_url; - - /// - /// packageUrl control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageUrl; - - /// - /// RequiredFieldValidator1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1; - - /// - /// pp_version control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_version; - - /// - /// packageVersion control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageVersion; - - /// - /// RequiredFieldValidator2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator2; - - /// - /// pp_icon control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_icon; - - /// - /// iconUrl control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox iconUrl; - - /// - /// pp_file control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_file; - - /// - /// packageUmbFile control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Literal packageUmbFile; - - /// - /// Pane5 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane5; - - /// - /// pp_umbracoVersion control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_umbracoVersion; - - /// - /// umbracoVersion control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox umbracoVersion; - - /// - /// RequiredFieldValidator7 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator7; - - /// - /// VersionValidator control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RegularExpressionValidator VersionValidator; - - /// - /// Pane1_1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane1_1; - - /// - /// pp_author control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_author; - - /// - /// packageAuthorName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageAuthorName; - - /// - /// RequiredFieldValidator3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator3; - - /// - /// pp_author_url control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_author_url; - - /// - /// packageAuthorUrl control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageAuthorUrl; - - /// - /// RequiredFieldValidator4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator4; - - /// - /// Pane1_2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane1_2; - - /// - /// pp_licens control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_licens; - - /// - /// packageLicenseName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageLicenseName; - - /// - /// RequiredFieldValidator5 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator5; - - /// - /// pp_license_url control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_license_url; - - /// - /// packageLicenseUrl control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageLicenseUrl; - - /// - /// RequiredFieldValidator6 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator6; - - /// - /// Pane1_3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane1_3; - - /// - /// pp_readme control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_readme; - - /// - /// packageReadme control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageReadme; - - /// - /// Pane2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2; - - /// - /// pp_content control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_content; - - /// - /// content control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder content; - - /// - /// packageContentSubdirs control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBox packageContentSubdirs; - - /// - /// packageContentSubdirsLabel control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Label packageContentSubdirsLabel; - - /// - /// Pane2_1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_1; - - /// - /// documentTypes control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList documentTypes; - - /// - /// Pane2_2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_2; - - /// - /// templates control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList templates; - - /// - /// Pane2_3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_3; - - /// - /// stylesheets control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList stylesheets; - - /// - /// Pane2_4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_4; - - /// - /// macros control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList macros; - - /// - /// Pane2_5 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_5; - - /// - /// languages control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList languages; - - /// - /// Pane2_6 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_6; - - /// - /// dictionary control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList dictionary; - - /// - /// Pane2_7 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane2_7; - - /// - /// cbl_datatypes control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList cbl_datatypes; - - /// - /// Pane3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane3; - - /// - /// Pane3_1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane3_1; - - /// - /// packageFilesRepeater control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Repeater packageFilesRepeater; - - /// - /// packageFilePathNew control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageFilePathNew; - - /// - /// createNewFilePath control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Button createNewFilePath; - - /// - /// Pane3_2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane3_2; - - /// - /// packageControlPath control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox packageControlPath; - - /// - /// Pane4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Umbraco.Web._Legacy.Controls.Pane Pane4; - - /// - /// actionsVal control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CustomValidator actionsVal; - - /// - /// tb_actions control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox tb_actions; - } -} From 091c9471bb3cc7b63b1f7870ebf6bebc07392024 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 10 Jan 2019 18:51:02 +1100 Subject: [PATCH 064/223] Gets macros in packages, gets the download button working to download a created package, more tests --- .../Models/Packaging/PackageDefinition.cs | 2 + src/Umbraco.Core/Packaging/PackageBuilder.cs | 22 +++++++--- .../src/views/packages/edit.controller.js | 24 +++++++++-- .../src/views/packages/edit.html | 25 +++++++++-- src/Umbraco.Web/Editors/PackageController.cs | 41 ++++++++++++++++++- 5 files changed, 101 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index 16934dc4c4..67d0c2970f 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; @@ -29,6 +30,7 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "folder")] public Guid FolderId { get; set; } + [ReadOnly(true)] [DataMember(Name = "packagePath")] public string PackagePath { get; set; } = string.Empty; diff --git a/src/Umbraco.Core/Packaging/PackageBuilder.cs b/src/Umbraco.Core/Packaging/PackageBuilder.cs index cc77f9bc78..6b26b09cbe 100644 --- a/src/Umbraco.Core/Packaging/PackageBuilder.cs +++ b/src/Umbraco.Core/Packaging/PackageBuilder.cs @@ -162,7 +162,9 @@ namespace Umbraco.Core.Packaging var actionsXml = new XElement("Actions"); try { - actionsXml.Add(XElement.Parse(definition.Actions)); + //this will be formatted like a full xml block like ... and we want the child nodes + var parsed = XElement.Parse(definition.Actions); + actionsXml.Add(parsed.Elements()); manifestRoot.Add(actionsXml); } catch (Exception e) @@ -596,7 +598,7 @@ namespace Umbraco.Core.Packaging Author = xml.Element("author")?.Value ?? string.Empty, AuthorUrl = xml.Element("author")?.AttributeValue("url") ?? string.Empty, Readme = xml.Element("readme")?.Value ?? string.Empty, - Actions = xml.Element("actions")?.ToString() ?? string.Empty, + Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? string.Empty, //take the entire outer xml value ContentNodeId = xml.Element("content")?.AttributeValue("nodeId") ?? string.Empty, ContentLoadChildNodes = xml.Element("content")?.AttributeValue("loadChildNodes") ?? false, Macros = xml.Element("macros")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), @@ -613,8 +615,18 @@ namespace Umbraco.Core.Packaging return retVal; } - private static XElement PackageDefinitionToXml(PackageDefinition def) + private XElement PackageDefinitionToXml(PackageDefinition def) { + var actionsXml = new XElement("actions"); + try + { + actionsXml = XElement.Parse(def.Actions); + } + catch (Exception e) + { + _logger.Warn(e, "Could not add package actions to the package xml definition, the xml did not parse"); + } + var packageXml = new XElement("package", new XAttribute("id", def.Id), new XAttribute("version", def.Version ?? string.Empty), @@ -634,8 +646,8 @@ namespace Umbraco.Core.Packaging new XCData(def.Author ?? string.Empty), new XAttribute("url", def.AuthorUrl ?? string.Empty)), - new XElement("readme", def.Readme ?? string.Empty), - new XElement("actions", def.Actions ?? string.Empty), + new XElement("readme", new XCData(def.Readme ?? string.Empty)), + actionsXml, new XElement("datatypes", string.Join(",", def.DataTypes ?? Array.Empty())), new XElement("content", diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 5f3832f79b..f351456609 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($scope, $location, $routeParams, entityResource, stylesheetResource, languageResource, packageResource, dictionaryResource, editorService, formHelper) { + function EditController($scope, $location, $routeParams, umbRequestHelper, entityResource, stylesheetResource, languageResource, packageResource, dictionaryResource, editorService, formHelper) { const vm = this; @@ -21,6 +21,7 @@ vm.removeFile = removeFile; vm.openControlPicker = openControlPicker; vm.removeControl = removeControl; + vm.downloadFile = downloadFile; const packageId = $routeParams.id; const create = $routeParams.create; @@ -76,8 +77,14 @@ vm.stylesheets = stylesheets; }); - // TODO: implement macros - vm.macros = []; + entityResource.getAll("Macro").then(macros => { + // a package stores the id as a string so we + // need to convert all ids to string for comparison + macros.forEach(macro => { + macro.id = macro.id.toString(); + }); + vm.macros = macros; + }); // get all languages languageResource.getAll().then(languages => { @@ -111,6 +118,17 @@ } + function downloadFile(id) { + var url = umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "DownloadCreatedPackage", + { id: id }); + + umbRequestHelper.downloadFile(url).then(function () { + + }); + } + function back() { $location.path("packages/packages/overview").search('create', null);; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index b1a417fd6f..20bc4277f8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -48,9 +48,10 @@ + @@ -170,7 +171,15 @@ - NOT IMPLEMENTED IN V8 YET +
+ +
+
@@ -301,6 +310,14 @@ + + + + + diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 66a0349417..0369e3eb24 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -1,9 +1,12 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Formatting; +using System.Net.Http.Headers; using System.Web.Http; +using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; @@ -33,7 +36,7 @@ namespace Umbraco.Web.Editors var package = Services.PackagingService.GetById(id); if (package == null) throw new HttpResponseException(HttpStatusCode.NotFound); - + return package; } @@ -75,6 +78,40 @@ namespace Umbraco.Web.Editors return Ok(); } - + + [HttpGet] + public HttpResponseMessage DownloadCreatedPackage(int id) + { + var package = Services.PackagingService.GetById(id); + if (package == null) + return Request.CreateResponse(HttpStatusCode.NotFound); + + var fullPath = IOHelper.MapPath(package.PackagePath); + if (!File.Exists(fullPath)) + return Request.CreateNotificationValidationErrorResponse("No file found for path " + package.PackagePath); + + var fileName = Path.GetFileName(package.PackagePath); + + var response = new HttpResponseMessage + { + Content = new StreamContent(File.OpenRead(fullPath)) + { + Headers = + { + ContentDisposition = new ContentDispositionHeaderValue("attachment") + { + FileName = fileName + }, + ContentType = new MediaTypeHeaderValue( "application/octet-stream") + } + } + }; + + // Set custom header so umbRequestHelper.downloadFile can save the correct filename + response.Headers.Add("x-filename", fileName); + + return response; + } + } } From 5cb99bfddceafccb44d900b5ed3ef2bec56a1709 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 10 Jan 2019 18:55:24 +1100 Subject: [PATCH 065/223] forgot to add the test class --- .../Packaging/PackageBuilderTests.cs | 200 ++++++++++++++++++ .../src/views/packages/edit.html | 3 - 2 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Tests/Packaging/PackageBuilderTests.cs diff --git a/src/Umbraco.Tests/Packaging/PackageBuilderTests.cs b/src/Umbraco.Tests/Packaging/PackageBuilderTests.cs new file mode 100644 index 0000000000..6368001c11 --- /dev/null +++ b/src/Umbraco.Tests/Packaging/PackageBuilderTests.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.IO; +using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Packaging; +using Umbraco.Core.Services; +using Umbraco.Tests.Services; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Packaging +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] + public class PackageBuilderTests : TestWithDatabaseBase + { + private Guid _testBaseFolder; + + public override void SetUp() + { + base.SetUp(); + _testBaseFolder = Guid.NewGuid(); + } + + public override void TearDown() + { + base.TearDown(); + + //clear out files/folders + Directory.Delete(IOHelper.MapPath("~/" + _testBaseFolder), true); + } + + public IPackageBuilder PackageBuilder => new PackageBuilder( + ServiceContext.ContentService, ServiceContext.ContentTypeService, ServiceContext.DataTypeService, + ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, + Factory.GetInstance(), Logger, + //temp paths + tempFolderPath: "~/" + _testBaseFolder + "/temp", + packagesFolderPath: "~/" + _testBaseFolder + "/packages", + mediaFolderPath: "~/" + _testBaseFolder + "/media"); + + [Test] + public void Delete() + { + var def1 = new PackageDefinition + { + Name = "test", + Url = "http://test.com", + Author = "Someone", + AuthorUrl = "http://test.com" + }; + + var result = PackageBuilder.SavePackage(def1); + Assert.IsTrue(result); + + PackageBuilder.Delete(def1.Id); + + def1 = PackageBuilder.GetById(def1.Id); + Assert.IsNull(def1); + } + + [Test] + public void Create_New() + { + var def1 = new PackageDefinition + { + Name = "test", + Url = "http://test.com", + Author = "Someone", + AuthorUrl = "http://test.com" + }; + + var result = PackageBuilder.SavePackage(def1); + + Assert.IsTrue(result); + Assert.AreEqual(1, def1.Id); + Assert.AreNotEqual(default(Guid).ToString(), def1.PackageId); + Assert.AreNotEqual(default(Guid).ToString(), def1.FolderId); + + var def2 = new PackageDefinition + { + Name = "test", + Url = "http://test.com", + Author = "Someone", + AuthorUrl = "http://test.com" + }; + + result = PackageBuilder.SavePackage(def2); + + Assert.IsTrue(result); + Assert.AreEqual(2, def2.Id); + Assert.AreNotEqual(default(Guid).ToString(), def2.PackageId); + Assert.AreNotEqual(default(Guid).ToString(), def2.FolderId); + } + + [Test] + public void Update_Not_Found() + { + var def = new PackageDefinition + { + Id = 3, //doesn't exist + Name = "test", + Url = "http://test.com", + Author = "Someone", + AuthorUrl = "http://test.com" + }; + + var result = PackageBuilder.SavePackage(def); + + Assert.IsFalse(result); + } + + [Test] + public void Update() + { + var def = new PackageDefinition + { + Name = "test", + Url = "http://test.com", + Author = "Someone", + AuthorUrl = "http://test.com" + }; + var result = PackageBuilder.SavePackage(def); + + def.Name = "updated"; + def.Files = new List {"hello.txt", "world.png"}; + result = PackageBuilder.SavePackage(def); + Assert.IsTrue(result); + + //re-get + def = PackageBuilder.GetById(def.Id); + Assert.AreEqual("updated", def.Name); + Assert.AreEqual(2, def.Files.Count); + //TODO: There's a whole lot more assertions to be done + + } + + [Test] + public void Export() + { + var file1 = $"~/{_testBaseFolder}/App_Plugins/MyPlugin/package.manifest"; + var file2 = $"~/{_testBaseFolder}/App_Plugins/MyPlugin/styles.css"; + var mappedFile1 = IOHelper.MapPath(file1); + var mappedFile2 = IOHelper.MapPath(file2); + Directory.CreateDirectory(Path.GetDirectoryName(mappedFile1)); + Directory.CreateDirectory(Path.GetDirectoryName(mappedFile2)); + File.WriteAllText(mappedFile1, "hello world"); + File.WriteAllText(mappedFile2, "hello world"); + + var def = new PackageDefinition + { + Name = "test", + Url = "http://test.com", + Author = "Someone", + AuthorUrl = "http://test.com", + Files = new List { file1, file2 }, + Actions = "" + }; + var result = PackageBuilder.SavePackage(def); + Assert.IsTrue(result); + Assert.IsTrue(def.PackagePath.IsNullOrWhiteSpace()); + + var zip = PackageBuilder.ExportPackage(def); + + def = PackageBuilder.GetById(def.Id); //re-get + Assert.IsNotNull(def.PackagePath); + + using (var archive = ZipFile.OpenRead(IOHelper.MapPath(zip))) + { + Assert.AreEqual(3, archive.Entries.Count); + + //the 2 files we manually added + Assert.IsNotNull(archive.Entries.Where(x => x.Name == "package.manifest")); + Assert.IsNotNull(archive.Entries.Where(x => x.Name == "styles.css")); + + //this is the actual package definition/manifest (not the developer manifest!) + var packageXml = archive.Entries.FirstOrDefault(x => x.Name == "package.xml"); + Assert.IsNotNull(packageXml); + + using (var stream = packageXml.Open()) + { + var xml = XDocument.Load(stream); + Assert.AreEqual("umbPackage", xml.Root.Name.ToString()); + Assert.AreEqual(2, xml.Root.Element("files").Elements("file").Count()); + + Assert.AreEqual("", xml.Element("umbPackage").Element("Actions").ToString(SaveOptions.DisableFormatting)); + + //TODO: There's a whole lot more assertions to be done + } + } + } + } +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 20bc4277f8..955676b806 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -158,7 +158,6 @@ -
{{vm.stylesheets | json }}
-
{{vm.package | json}}
- From 568d5c2583baf8bb691283ba406e0817718d0712 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 10 Jan 2019 19:08:52 +1100 Subject: [PATCH 066/223] Fixes issue with redirect --- src/Umbraco.Core/Models/Packaging/PackageDefinition.cs | 2 +- src/Umbraco.Core/Packaging/PackageBuilder.cs | 2 +- src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index 67d0c2970f..01d10fa2e1 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -94,7 +94,7 @@ namespace Umbraco.Core.Models.Packaging public string LoadControl { get; set; } = string.Empty; [DataMember(Name = "actions")] - public string Actions { get; set; } + public string Actions { get; set; } = ""; [DataMember(Name = "dataTypes")] public IList DataTypes { get; set; } = new List(); diff --git a/src/Umbraco.Core/Packaging/PackageBuilder.cs b/src/Umbraco.Core/Packaging/PackageBuilder.cs index 6b26b09cbe..ae5accf794 100644 --- a/src/Umbraco.Core/Packaging/PackageBuilder.cs +++ b/src/Umbraco.Core/Packaging/PackageBuilder.cs @@ -598,7 +598,7 @@ namespace Umbraco.Core.Packaging Author = xml.Element("author")?.Value ?? string.Empty, AuthorUrl = xml.Element("author")?.AttributeValue("url") ?? string.Empty, Readme = xml.Element("readme")?.Value ?? string.Empty, - Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? string.Empty, //take the entire outer xml value + Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value ContentNodeId = xml.Element("content")?.AttributeValue("nodeId") ?? string.Empty, ContentLoadChildNodes = xml.Element("content")?.AttributeValue("loadChildNodes") ?? false, Macros = xml.Element("macros")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index f351456609..057f1160c2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -146,7 +146,7 @@ if (create) { //if we are creating, then redirect to the correct url and reload - $location.path("packages/packages/overview/" + vm.package.id).search("subview", "created"); + $location.path("packages/packages/edit/" + vm.package.id).search("subview", "created").search("create", null); //don't add a browser history for this $location.replace(); } From 4bf3c1d05b9b228246e580c63785b72b83833311 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 10 Jan 2019 19:27:25 +1100 Subject: [PATCH 067/223] Handles trying to create a package with a duplicate name --- src/Umbraco.Core/Packaging/PackageBuilder.cs | 5 +++++ .../src/common/services/formhelper.service.js | 10 +++++----- src/Umbraco.Web/Editors/PackageController.cs | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackageBuilder.cs b/src/Umbraco.Core/Packaging/PackageBuilder.cs index ae5accf794..523ed6ed93 100644 --- a/src/Umbraco.Core/Packaging/PackageBuilder.cs +++ b/src/Umbraco.Core/Packaging/PackageBuilder.cs @@ -87,6 +87,11 @@ namespace Umbraco.Core.Packaging if (definition.Id == default) { + //check if the name already exists + var existsByName = packagesXml.Root.Elements("package").Any(x => x.AttributeValue("name") == definition.Name); + if (existsByName) + return false; + //need to gen an id and persist // Find max id var maxId = packagesXml.Root.Elements("package").Max(x => x.AttributeValue("id")) ?? 0; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js index b21909f573..191e0a22c0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js @@ -110,7 +110,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService //Or, some strange server error if (err.status === 400) { //now we need to look through all the validation errors - if (err.data && (err.data.ModelState)) { + if (err.data && err.data.ModelState) { //wire up the server validation errs this.handleServerValidation(err.data.ModelState); @@ -118,11 +118,11 @@ function formHelper(angularHelper, serverValidationManager, notificationsService //execute all server validation events and subscribers serverValidationManager.notifyAndClearAllSubscriptions(); } - else { + } + else { - //TODO: All YSOD handling should be done with an interceptor - overlayService.ysod(err); - } + //TODO: All YSOD handling should be done with an interceptor + overlayService.ysod(err); } }, diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 0369e3eb24..215c81faac 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -57,7 +57,11 @@ namespace Umbraco.Web.Editors //save it if (!Services.PackagingService.SavePackage(model)) - throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("The package with id {definition.Id} was not found")); + throw new HttpResponseException( + Request.CreateNotificationValidationErrorResponse( + model.Id == default + ? $"A package with the name {model.Name} already exists" + : $"The package with id {model.Id} was not found")); Services.PackagingService.ExportPackage(model); From 003907358dd7a273992e930d49ca2303e86b50af Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 10 Jan 2019 14:03:25 +0100 Subject: [PATCH 068/223] Better runtime state detection, to support auto-install --- .../Components/RuntimeLevelAttribute.cs | 15 +++- src/Umbraco.Core/IRuntimeState.cs | 5 ++ .../Install/DatabaseSchemaCreator.cs | 12 ++-- .../Persistence/IUmbracoDatabaseFactory.cs | 6 ++ .../Persistence/UmbracoDatabaseFactory.cs | 11 +++ src/Umbraco.Core/Runtime/CoreRuntime.cs | 3 +- src/Umbraco.Core/RuntimeLevel.cs | 3 + src/Umbraco.Core/RuntimeLevelReason.cs | 68 +++++++++++++++++++ src/Umbraco.Core/RuntimeState.cs | 43 ++++++++++-- src/Umbraco.Core/Umbraco.Core.csproj | 1 + 10 files changed, 153 insertions(+), 14 deletions(-) create mode 100644 src/Umbraco.Core/RuntimeLevelReason.cs diff --git a/src/Umbraco.Core/Components/RuntimeLevelAttribute.cs b/src/Umbraco.Core/Components/RuntimeLevelAttribute.cs index 51920660d4..2c698a671a 100644 --- a/src/Umbraco.Core/Components/RuntimeLevelAttribute.cs +++ b/src/Umbraco.Core/Components/RuntimeLevelAttribute.cs @@ -1,13 +1,22 @@ using System; +using Umbraco.Core.Composing; namespace Umbraco.Core.Components { + /// + /// Marks a composer to indicate a minimum and/or maximum runtime level for which the composer would compose. + /// [AttributeUsage(AttributeTargets.Class /*, AllowMultiple = false, Inherited = true*/)] public class RuntimeLevelAttribute : Attribute { - //public RuntimeLevelAttribute() - //{ } + /// + /// Gets or sets the minimum runtime level for which the composer would compose. + /// + public RuntimeLevel MinLevel { get; set; } = RuntimeLevel.Install; - public RuntimeLevel MinLevel { get; set; } = RuntimeLevel.Boot; + /// + /// Gets or sets the maximum runtime level for which the composer would compose. + /// + public RuntimeLevel MaxLevel { get; set; } = RuntimeLevel.Run; } } diff --git a/src/Umbraco.Core/IRuntimeState.cs b/src/Umbraco.Core/IRuntimeState.cs index 5fcfab1518..30c768ab01 100644 --- a/src/Umbraco.Core/IRuntimeState.cs +++ b/src/Umbraco.Core/IRuntimeState.cs @@ -57,6 +57,11 @@ namespace Umbraco.Core /// RuntimeLevel Level { get; } + /// + /// Gets the reason for the runtime level of execution. + /// + RuntimeLevelReason Reason { get; } + /// /// Gets the current migration state. /// diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs index 5525cc4a50..f9f3e5da30 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Migrations.Install /// /// Creates the initial database schema during install. /// - internal class DatabaseSchemaCreator + public class DatabaseSchemaCreator { private readonly IUmbracoDatabase _database; private readonly ILogger _logger; @@ -28,7 +28,7 @@ namespace Umbraco.Core.Migrations.Install private ISqlSyntaxProvider SqlSyntax => _database.SqlContext.SqlSyntax; // all tables, in order - public static readonly List OrderedTables = new List + internal static readonly List OrderedTables = new List { typeof (UserDto), typeof (NodeDto), @@ -138,7 +138,7 @@ namespace Umbraco.Core.Migrations.Install /// /// Validates the schema of the current database. /// - public DatabaseSchemaResult ValidateSchema() + internal DatabaseSchemaResult ValidateSchema() { var result = new DatabaseSchemaResult(SqlSyntax); @@ -387,7 +387,7 @@ namespace Umbraco.Core.Migrations.Install /// If has been decorated with an , the name from that /// attribute will be used for the table name. If the attribute is not present, the name /// will be used instead. - /// + /// /// If a table with the same name already exists, the parameter will determine /// whether the table is overwritten. If true, the table will be overwritten, whereas this method will /// not do anything if the parameter is false. @@ -409,14 +409,14 @@ namespace Umbraco.Core.Migrations.Install /// If has been decorated with an , the name from /// that attribute will be used for the table name. If the attribute is not present, the name /// will be used instead. - /// + /// /// If a table with the same name already exists, the parameter will determine /// whether the table is overwritten. If true, the table will be overwritten, whereas this method will /// not do anything if the parameter is false. /// /// This need to execute as part of a transaction. /// - public void CreateTable(bool overwrite, Type modelType, DatabaseDataCreator dataCreation) + internal void CreateTable(bool overwrite, Type modelType, DatabaseDataCreator dataCreation) { if (!_database.InTransaction) throw new InvalidOperationException("Database is not in a transaction."); diff --git a/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs index 9ef320e187..0236fc4bd5 100644 --- a/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/IUmbracoDatabaseFactory.cs @@ -18,6 +18,12 @@ namespace Umbraco.Core.Persistence /// bool Configured { get; } + /// + /// Gets the connection string. + /// + /// Throws if the factory is not configured. + string ConnectionString { get; } + /// /// Gets a value indicating whether the database can connect. /// diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs index c9a509fe94..9ed52ca148 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs @@ -2,6 +2,7 @@ using System.Configuration; using System.Data.Common; using System.Threading; +using LightInject; using NPoco; using NPoco.FluentMappings; using Umbraco.Core.Exceptions; @@ -102,6 +103,16 @@ namespace Umbraco.Core.Persistence /// public bool Configured { get; private set; } + /// + public string ConnectionString + { + get + { + EnsureConfigured(); + return _connectionString; + } + } + /// public bool CanConnect { diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 5d2359d04c..d6f68d339f 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -252,7 +252,7 @@ namespace Umbraco.Core.Runtime { _state.DetermineRuntimeLevel(databaseFactory, profilingLogger); - profilingLogger.Debug("Runtime level: {RuntimeLevel}", _state.Level); + profilingLogger.Debug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", _state.Level, _state.Reason); if (_state.Level == RuntimeLevel.Upgrade) { @@ -263,6 +263,7 @@ namespace Umbraco.Core.Runtime catch { _state.Level = RuntimeLevel.BootFailed; + _state.Reason = RuntimeLevelReason.BootFailedOnException; timer.Fail(); throw; } diff --git a/src/Umbraco.Core/RuntimeLevel.cs b/src/Umbraco.Core/RuntimeLevel.cs index f9ec3c90c5..2645e89226 100644 --- a/src/Umbraco.Core/RuntimeLevel.cs +++ b/src/Umbraco.Core/RuntimeLevel.cs @@ -1,5 +1,8 @@ namespace Umbraco.Core { + /// + /// Describes the levels in which the runtime can run. + /// public enum RuntimeLevel { /// diff --git a/src/Umbraco.Core/RuntimeLevelReason.cs b/src/Umbraco.Core/RuntimeLevelReason.cs new file mode 100644 index 0000000000..c10ac8b206 --- /dev/null +++ b/src/Umbraco.Core/RuntimeLevelReason.cs @@ -0,0 +1,68 @@ +namespace Umbraco.Core +{ + /// + /// Describes the reason for the runtime level. + /// + public enum RuntimeLevelReason + { + /// + /// The code version is lower than the version indicated in web.config, and + /// downgrading Umbraco is not supported. + /// + BootFailedCannotDowngrade, + + /// + /// The runtime cannot connect to the configured database. + /// + BootFailedCannotConnectToDatabase, + + /// + /// The runtime can connect to the configured database, but it cannot + /// retrieve the migrations status. + /// + BootFailedCannotCheckUpgradeState, + + /// + /// An exception was thrown during boot. + /// + BootFailedOnException, + + /// + /// Umbraco is not installed at all. + /// + InstallNoVersion, + + /// + /// A version is specified in web.config but the database is not configured. + /// + /// This is a weird state. + InstallNoDatabase, + + /// + /// A version is specified in web.config and a database is configured, but the + /// database is missing, and installing over a missing database has been enabled. + /// + InstallMissingDatabase, + + /// + /// A version is specified in web.config and a database is configured, but the + /// database is empty, and installing over an empty database has been enabled. + /// + InstallEmptyDatabase, + + /// + /// Umbraco runs an old version. + /// + UpgradeOldVersion, + + /// + /// Umbraco runs the current version but some migrations have not run. + /// + UpgradeMigrations, + + /// + /// Umbraco is running. + /// + Run + } +} diff --git a/src/Umbraco.Core/RuntimeState.cs b/src/Umbraco.Core/RuntimeState.cs index df2ee44a7d..e344a67920 100644 --- a/src/Umbraco.Core/RuntimeState.cs +++ b/src/Umbraco.Core/RuntimeState.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Configuration; using System.Threading; using System.Web; using Semver; @@ -93,6 +94,9 @@ namespace Umbraco.Core internal set { _level = value; if (value == RuntimeLevel.Run) _runLevel.Set(); } } + /// + public RuntimeLevelReason Reason { get; internal set; } + /// /// Ensures that the property has a value. /// @@ -129,6 +133,11 @@ namespace Umbraco.Core /// public BootFailedException BootFailedException { get; internal set; } + // currently configured via app settings + private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing; + private bool InstallMissingDatabase { get; } = BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false); + private bool InstallEmptyDatabase { get; } = BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false); + /// /// Determines the runtime level. /// @@ -143,6 +152,7 @@ namespace Umbraco.Core // there is no local version, we are not installed logger.Debug("No local version, need to install Umbraco."); Level = RuntimeLevel.Install; + Reason = RuntimeLevelReason.InstallNoVersion; return; } @@ -152,12 +162,14 @@ namespace Umbraco.Core // need to upgrade logger.Debug("Local version '{LocalVersion}' < code version '{CodeVersion}', need to upgrade Umbraco.", localVersion, codeVersion); Level = RuntimeLevel.Upgrade; + Reason = RuntimeLevelReason.UpgradeOldVersion; } else if (localVersion > codeVersion) { logger.Warn("Local version '{LocalVersion}' > code version '{CodeVersion}', downgrading is not supported.", localVersion, codeVersion); // in fact, this is bad enough that we want to throw + Reason = RuntimeLevelReason.BootFailedCannotDowngrade; throw new BootFailedException($"Local version \"{localVersion}\" > code version \"{codeVersion}\", downgrading is not supported."); } else if (databaseFactory.Configured == false) @@ -166,16 +178,18 @@ namespace Umbraco.Core // install (again? this is a weird situation...) logger.Debug("Database is not configured, need to install Umbraco."); Level = RuntimeLevel.Install; + Reason = RuntimeLevelReason.InstallNoDatabase; return; } // else, keep going, // anything other than install wants a database - see if we can connect // (since this is an already existing database, assume localdb is ready) - for (var i = 0; i < 5; i++) + var tries = InstallMissingDatabase ? 2 : 5; + for (var i = 0;;) { connect = databaseFactory.CanConnect; - if (connect) break; + if (connect || ++i == tries) break; logger.Debug("Could not immediately connect to database, trying again."); Thread.Sleep(1000); } @@ -185,7 +199,16 @@ namespace Umbraco.Core // cannot connect to configured database, this is bad, fail logger.Debug("Could not connect to database."); - // in fact, this is bad enough that we want to throw + if (InstallMissingDatabase) + { + // ok to install on a configured but missing database + Level = RuntimeLevel.Install; + Reason = RuntimeLevelReason.InstallMissingDatabase; + return; + } + + // else it is bad enough that we want to throw + Reason = RuntimeLevelReason.BootFailedCannotConnectToDatabase; throw new BootFailedException("A connection string is configured but Umbraco could not connect to the database."); } @@ -195,7 +218,6 @@ namespace Umbraco.Core // else // look for a matching migration entry - bypassing services entirely - they are not 'up' yet - // fixme - in a LB scenario, ensure that the DB gets upgraded only once! bool noUpgrade; try { @@ -205,6 +227,17 @@ namespace Umbraco.Core { // can connect to the database but cannot check the upgrade state... oops logger.Warn(e, "Could not check the upgrade state."); + + if (InstallEmptyDatabase) + { + // ok to install on an empty database + Level = RuntimeLevel.Install; + Reason = RuntimeLevelReason.InstallEmptyDatabase; + return; + } + + // else it is bad enough that we want to throw + Reason = RuntimeLevelReason.BootFailedCannotCheckUpgradeState; throw new BootFailedException("Could not check the upgrade state.", e); } @@ -216,6 +249,7 @@ namespace Umbraco.Core { // the database version matches the code & files version, all clear, can run Level = RuntimeLevel.Run; + Reason = RuntimeLevelReason.Run; return; } @@ -226,6 +260,7 @@ namespace Umbraco.Core // which means the local files have been upgraded but not the database - need to upgrade logger.Debug("Has not reached the final upgrade step, need to upgrade Umbraco."); Level = RuntimeLevel.Upgrade; + Reason = RuntimeLevelReason.UpgradeMigrations; } protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index a01bbf1746..fd5dfe9294 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -490,6 +490,7 @@ + From 74c01af3695e218aa30d5397a22d24ed856b6e06 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 11 Jan 2019 10:35:37 +1100 Subject: [PATCH 069/223] Splits logic for IPackageBuilder into ICreatedPackagesRepository and IInstalledPackagesRepository since it's nearly the same for both --- .../Composing/Composers/ServicesComposer.cs | 4 +- ...uilder.cs => CreatedPackagesRepository.cs} | 8 +- .../Packaging/ICreatedPackagesRepository.cs | 13 + .../Packaging/IInstalledPackagesRepository.cs | 14 + ...der.cs => IPackageDefinitionRepository.cs} | 15 +- .../Services/IPackagingService.cs | 12 +- .../Services/Implement/PackagingService.cs | 16 +- src/Umbraco.Core/Umbraco.Core.csproj | 6 +- ...s.cs => CreatedPackagesRepositoryTests.cs} | 4 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- src/Umbraco.Web/Editors/PackageController.cs | 18 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 - .../_Legacy/Controls/BaseTreePicker.cs | 299 ------------------ .../PackageInstance/InstalledPackage.cs | 77 +---- .../umbraco/controls/ContentPicker.cs | 60 ---- 16 files changed, 66 insertions(+), 486 deletions(-) rename src/Umbraco.Core/Packaging/{PackageBuilder.cs => CreatedPackagesRepository.cs} (98%) create mode 100644 src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs create mode 100644 src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs rename src/Umbraco.Core/Packaging/{IPackageBuilder.cs => IPackageDefinitionRepository.cs} (61%) rename src/Umbraco.Tests/Packaging/{PackageBuilderTests.cs => CreatedPackagesRepositoryTests.cs} (97%) delete mode 100644 src/Umbraco.Web/_Legacy/Controls/BaseTreePicker.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentPicker.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 6395a2c6db..9692a2d87c 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -60,8 +60,8 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(); composition.RegisterUnique(); - composition.RegisterUnique(factory => - new PackageBuilder( //we are using a factory because there are optional ctor args + composition.RegisterUnique(factory => + new CreatedPackagesRepository( //we are using a factory because there are optional ctor args factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance())); diff --git a/src/Umbraco.Core/Packaging/PackageBuilder.cs b/src/Umbraco.Core/Packaging/CreatedPackagesRepository.cs similarity index 98% rename from src/Umbraco.Core/Packaging/PackageBuilder.cs rename to src/Umbraco.Core/Packaging/CreatedPackagesRepository.cs index 523ed6ed93..169b161fbc 100644 --- a/src/Umbraco.Core/Packaging/PackageBuilder.cs +++ b/src/Umbraco.Core/Packaging/CreatedPackagesRepository.cs @@ -15,7 +15,7 @@ using File = System.IO.File; namespace Umbraco.Core.Packaging { - internal class PackageBuilder : IPackageBuilder + internal class CreatedPackagesRepository : ICreatedPackagesRepository { private readonly IContentService _contentService; private readonly IContentTypeService _contentTypeService; @@ -29,7 +29,7 @@ namespace Umbraco.Core.Packaging private readonly string _packagesFolderPath; private readonly string _tempFolderPath; - public PackageBuilder(IContentService contentService, IContentTypeService contentTypeService, + public CreatedPackagesRepository(IContentService contentService, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, IMacroService macroService, ILocalizationService languageService, IEntityXmlSerializer serializer, ILogger logger, @@ -174,7 +174,7 @@ namespace Umbraco.Core.Packaging } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); + _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); } } @@ -629,7 +629,7 @@ namespace Umbraco.Core.Packaging } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package xml definition, the xml did not parse"); + _logger.Warn(e, "Could not add package actions to the package xml definition, the xml did not parse"); } var packageXml = new XElement("package", diff --git a/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs b/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs new file mode 100644 index 0000000000..52a16ddff0 --- /dev/null +++ b/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs @@ -0,0 +1,13 @@ +using Umbraco.Core.Models.Packaging; + +namespace Umbraco.Core.Packaging +{ + public interface ICreatedPackagesRepository : IPackageDefinitionRepository + { + /// + /// Creates the package file and returns it's physical path + /// + /// + string ExportPackage(PackageDefinition definition); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs b/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs new file mode 100644 index 0000000000..3d601d6b1d --- /dev/null +++ b/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs @@ -0,0 +1,14 @@ +using System; + +namespace Umbraco.Core.Packaging +{ + + //TODO: We need to figure out how we want to do this + // we have 2x repositories for saving created and installed packages + // created packages can also be exported + // maybe the below will work? + + public interface IInstalledPackagesRepository : IPackageDefinitionRepository + { + } +} diff --git a/src/Umbraco.Core/Packaging/IPackageBuilder.cs b/src/Umbraco.Core/Packaging/IPackageDefinitionRepository.cs similarity index 61% rename from src/Umbraco.Core/Packaging/IPackageBuilder.cs rename to src/Umbraco.Core/Packaging/IPackageDefinitionRepository.cs index 5a7449545f..343a0a05ea 100644 --- a/src/Umbraco.Core/Packaging/IPackageBuilder.cs +++ b/src/Umbraco.Core/Packaging/IPackageDefinitionRepository.cs @@ -1,13 +1,12 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Models.Packaging; namespace Umbraco.Core.Packaging { /// - /// Creates packages + /// Defines methods for persisting package definitions to storage /// - public interface IPackageBuilder + public interface IPackageDefinitionRepository { IEnumerable GetAll(); PackageDefinition GetById(int id); @@ -20,11 +19,5 @@ namespace Umbraco.Core.Packaging /// true if creating/updating the package was successful, otherwise false /// bool SavePackage(PackageDefinition definition); - - /// - /// Creates the package file and returns it's physical path - /// - /// - string ExportPackage(PackageDefinition definition); } -} +} \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 4d60f3dca4..32d5cd4c59 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -9,23 +9,23 @@ namespace Umbraco.Core.Services { public interface IPackagingService : IService { - #region Package Building + #region Created Packages - IEnumerable GetAll(); - PackageDefinition GetById(int id); - void Delete(int id); + IEnumerable GetAllCreatedPackages(); + PackageDefinition GetCreatedPackageById(int id); + void DeleteCreatedPackage(int id); /// /// Persists a package definition to storage /// /// - bool SavePackage(PackageDefinition definition); + bool SaveCreatedPackage(PackageDefinition definition); /// /// Creates the package file and returns it's physical path /// /// - string ExportPackage(PackageDefinition definition); + string ExportCreatedPackage(PackageDefinition definition); #endregion diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 17959f0983..d6003dc842 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -46,7 +46,7 @@ namespace Umbraco.Core.Services.Implement private readonly IAuditRepository _auditRepository; private readonly IContentTypeRepository _contentTypeRepository; private readonly PropertyEditorCollection _propertyEditors; - private readonly IPackageBuilder _packageBuilder; + private readonly ICreatedPackagesRepository _createdPackages; private static HttpClient _httpClient; public PackagingService( @@ -62,7 +62,7 @@ namespace Umbraco.Core.Services.Implement IAuditRepository auditRepository, IContentTypeRepository contentTypeRepository, PropertyEditorCollection propertyEditors, - IPackageBuilder packageBuilder) + ICreatedPackagesRepository createdPackages) { _logger = logger; _contentService = contentService; @@ -76,7 +76,7 @@ namespace Umbraco.Core.Services.Implement _auditRepository = auditRepository; _contentTypeRepository = contentTypeRepository; _propertyEditors = propertyEditors; - _packageBuilder = packageBuilder; + _createdPackages = createdPackages; _importedContentTypes = new Dictionary(); } @@ -1402,15 +1402,15 @@ namespace Umbraco.Core.Services.Implement #region Package Building - public void Delete(int id) => _packageBuilder.Delete(id); + public void DeleteCreatedPackage(int id) => _createdPackages.Delete(id); - public IEnumerable GetAll() => _packageBuilder.GetAll(); + public IEnumerable GetAllCreatedPackages() => _createdPackages.GetAll(); - public PackageDefinition GetById(int id) => _packageBuilder.GetById(id); + public PackageDefinition GetCreatedPackageById(int id) => _createdPackages.GetById(id); - public bool SavePackage(PackageDefinition definition) => _packageBuilder.SavePackage(definition); + public bool SaveCreatedPackage(PackageDefinition definition) => _createdPackages.SavePackage(definition); - public string ExportPackage(PackageDefinition definition) => _packageBuilder.ExportPackage(definition); + public string ExportCreatedPackage(PackageDefinition definition) => _createdPackages.ExportPackage(definition); #endregion diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 00179f562a..bad9ba7ccd 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -444,9 +444,11 @@ - + + + - + diff --git a/src/Umbraco.Tests/Packaging/PackageBuilderTests.cs b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs similarity index 97% rename from src/Umbraco.Tests/Packaging/PackageBuilderTests.cs rename to src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs index 6368001c11..3bd9b50ed4 100644 --- a/src/Umbraco.Tests/Packaging/PackageBuilderTests.cs +++ b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs @@ -19,7 +19,7 @@ namespace Umbraco.Tests.Packaging { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class PackageBuilderTests : TestWithDatabaseBase + public class CreatedPackagesRepositoryTests : TestWithDatabaseBase { private Guid _testBaseFolder; @@ -37,7 +37,7 @@ namespace Umbraco.Tests.Packaging Directory.Delete(IOHelper.MapPath("~/" + _testBaseFolder), true); } - public IPackageBuilder PackageBuilder => new PackageBuilder( + public ICreatedPackagesRepository PackageBuilder => new CreatedPackagesRepository( ServiceContext.ContentService, ServiceContext.ContentTypeService, ServiceContext.DataTypeService, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, Factory.GetInstance(), Logger, diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index c6602fc54e..105bc440cc 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -170,7 +170,7 @@ namespace Umbraco.Tests.TestHelpers var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); var packagingService = GetLazyService(factory, c => new PackagingService( logger, contentService.Value, contentTypeService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, scopeProvider, GetRepo(c), GetRepo(c), new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())), - new PackageBuilder(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new CreatedPackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger))); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 3e619c6f00..7ea7d5d8b1 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -142,7 +142,7 @@ - + diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 215c81faac..86f3e48b7c 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -1,23 +1,17 @@ using System.Collections.Generic; using System.IO; -using System.Linq; using System.Net; using System.Net.Http; -using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Web.Http; using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; -using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; -using Umbraco.Web._Legacy.Packager.PackageInstance; namespace Umbraco.Web.Editors { - //TODO: Packager stuff still lives in business logic - YUK - /// /// A controller used for installing packages and managing all of the data in the packages section in the back office /// @@ -28,12 +22,12 @@ namespace Umbraco.Web.Editors { public IEnumerable GetCreatedPackages() { - return Services.PackagingService.GetAll(); + return Services.PackagingService.GetAllCreatedPackages(); } public PackageDefinition GetCreatedPackageById(int id) { - var package = Services.PackagingService.GetById(id); + var package = Services.PackagingService.GetCreatedPackageById(id); if (package == null) throw new HttpResponseException(HttpStatusCode.NotFound); @@ -56,14 +50,14 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); //save it - if (!Services.PackagingService.SavePackage(model)) + if (!Services.PackagingService.SaveCreatedPackage(model)) throw new HttpResponseException( Request.CreateNotificationValidationErrorResponse( model.Id == default ? $"A package with the name {model.Name} already exists" : $"The package with id {model.Id} was not found")); - Services.PackagingService.ExportPackage(model); + Services.PackagingService.ExportCreatedPackage(model); //the packagePath will be on the model return model; @@ -78,7 +72,7 @@ namespace Umbraco.Web.Editors [HttpDelete] public IHttpActionResult DeleteCreatedPackage(int packageId) { - Services.PackagingService.Delete(packageId); + Services.PackagingService.DeleteCreatedPackage(packageId); return Ok(); } @@ -86,7 +80,7 @@ namespace Umbraco.Web.Editors [HttpGet] public HttpResponseMessage DownloadCreatedPackage(int id) { - var package = Services.PackagingService.GetById(id); + var package = Services.PackagingService.GetCreatedPackageById(id); if (package == null) return Request.CreateResponse(HttpStatusCode.NotFound); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b9a6c17ef7..ed423b509b 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1126,7 +1126,6 @@ - @@ -1224,7 +1223,6 @@ Code - FeedProxy.aspx diff --git a/src/Umbraco.Web/_Legacy/Controls/BaseTreePicker.cs b/src/Umbraco.Web/_Legacy/Controls/BaseTreePicker.cs deleted file mode 100644 index c2298e4906..0000000000 --- a/src/Umbraco.Web/_Legacy/Controls/BaseTreePicker.cs +++ /dev/null @@ -1,299 +0,0 @@ -using System; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Web.UI.HtmlControls; -using Umbraco.Core.Composing; -using Umbraco.Core.Services; - -namespace Umbraco.Web._Legacy.Controls -{ - [ValidationProperty("Value")] - public abstract class BaseTreePicker : Control, INamingContainer - { - - protected HiddenField ItemIdValue; - protected HtmlAnchor DeleteLink; - protected HtmlAnchor ChooseLink; - protected HtmlGenericControl ItemTitle; - protected HtmlGenericControl ButtonContainer; - protected HtmlGenericControl RootContainer; - - public BaseTreePicker() - { - ShowDelete = true; - ModalHeight = 400; - ModalWidth = 300; - ShowHeader = true; - } - - /// - /// Wraps the hidden vield value - /// - public string Value - { - get - { - EnsureChildControls(); - return ItemIdValue.Value; - } - set - { - EnsureChildControls(); - ItemIdValue.Value = value; - } - } - - public int ModalWidth { get; set; } - public int ModalHeight { get; set; } - public bool ShowDelete { get; set; } - public bool ShowHeader { get; set; } - - /// - /// Need to specify the tree picker url (iframe) - /// - public abstract string TreePickerUrl { get; } - - /// - /// The title to specify for the picker window - /// - public abstract string ModalWindowTitle { get; } - - /// - /// If item has been selected or stored, this will query the db for its title - /// - protected virtual string GetItemTitle() - { - if (!string.IsNullOrEmpty(ItemIdValue.Value)) - { - try - { - return Current.Services.EntityService.Get(int.Parse(ItemIdValue.Value)).Name; - } - catch (ArgumentException) { /*the node does not exist! we will ignore*/ } - } - return ""; - } - - /// - /// Just like GetItemTitle, except returns the full path (breadcrumbs) of the node - /// - protected virtual string GetItemBreadcrumbs() - { - //TODO: Shouldn't this use the same/similar logic as the EntityController.GetResultForAncestors ? - - if (!string.IsNullOrEmpty(ItemIdValue.Value)) - { - try - { - int nodeId = -1; - if (int.TryParse(ItemIdValue.Value, out nodeId)) - { - var n = Current.Services.EntityService.Get(nodeId); - string title = n.Name; - string separator = " > "; - while (n.Level > 1) - { - n = Current.Services.EntityService.Get(n.ParentId); - title = n.Name + separator + title; - } - return title; - } - else - { - return ItemIdValue.Value; - } - - } - catch (ArgumentException) { /*the node does not exist! we will ignore*/ } - } - return ""; - } - - /// - /// Outputs the JavaScript instances used to make this control work - /// - protected virtual string GetJSScript() - { - /* 0 = this control's client id - * 1 = label - * 2 = itemIdValueClientID - * 3 = itemTitleClientID - * 4 = itemPickerUrl - * 5 = popup width - * 6 = popup height - * 7 = show header - * 8 = umbraco path - */ - return string.Format(@" - var mc_{0} = new Umbraco.Controls.TreePicker('{0}','{1}','{2}','{3}','{4}',{5},{6},{7},'{8}');", - new string[] - { - this.ClientID, - ModalWindowTitle, - ItemIdValue.ClientID, - ItemTitle.ClientID, - TreePickerUrl, - ModalWidth.ToString(), - ModalHeight.ToString(), - ShowHeader.ToString().ToLower(), - Umbraco.Core.IO.IOHelper.ResolveUrl(Umbraco.Core.IO.SystemDirectories.Umbraco).TrimEnd('/') - }); - } - - /// - /// Registers the required JS classes required to make this control work - /// - protected virtual void RenderJSComponents() - { - const string BaseTreePickerScriptJs = @"/// -(function ($) { - $(document).ready(function () { - // Tooltip only Text - $('.umb-tree-picker a.choose').click(function () { - var that = this; - var s = $(that).data(""section""); - UmbClientMgr.openAngularModalWindow({ - template: 'views/common/dialogs/treepicker.html', - section: s, - callback: function (data) { - //this returns the content object picked - var p = jQuery(that).parent(); - p.find("".buttons"").show(); - - p.find(""input"").val(data.id); - p.find("".treePickerTitle"").text(data.name).show(); - p.find("".clear"").show(); - } - }); - - return false; - }); - - $('.umb-tree-picker a.clear').click(function () { - jQuery(this).parent().parent().find(""input"").val(""-1""); - jQuery(this).parent().parent().find("".treePickerTitle"").text("""").hide(); - jQuery(this).hide(); - }); - }); -})(jQuery); -"; - - const string scriptKey = "BaseTreePickerScripts"; - if (ScriptManager.GetCurrent(Page).IsInAsyncPostBack) - { - ScriptManager.RegisterStartupScript(this, this.GetType(), scriptKey, BaseTreePickerScriptJs, true); - } - else - { - Page.ClientScript.RegisterClientScriptBlock(typeof(BaseTreePicker), scriptKey, BaseTreePickerScriptJs, true); - } - } - - protected override void OnInit(EventArgs e) - { - base.OnInit(e); - - EnsureChildControls(); - - //disable view state for this control - this.EnableViewState = false; - } - - /// - /// Create the native .net child controls for this control - /// - protected override void CreateChildControls() - { - base.CreateChildControls(); - - RootContainer = new HtmlGenericControl("span"); - RootContainer.Attributes.Add("class", "umb-tree-picker"); - this.Controls.Add(RootContainer); - - //create the hidden field - ItemIdValue = new HiddenField(); - ItemIdValue.ID = "ContentIdValue"; - RootContainer.Controls.Add(ItemIdValue); - - - ButtonContainer = new HtmlGenericControl("span"); - ButtonContainer.ID = "btns"; - - //add item title with padding - ItemTitle = new HtmlGenericControl("span"); - ItemTitle.ID = "title"; - ItemTitle.Style.Add(HtmlTextWriterStyle.FontWeight, "bold"); - ItemTitle.Attributes.Add("class", "treePickerTitle"); // solely for styling, e.g. with an underline or dotted border, etc. - ButtonContainer.Controls.Add(ItemTitle); - ButtonContainer.Attributes.Add("class", "buttons"); - ButtonContainer.Controls.Add(new LiteralControl(" ")); - ButtonContainer.Controls.Add(new LiteralControl(" ")); - - //add the delete link with padding - DeleteLink = new HtmlAnchor(); - DeleteLink.HRef = "#"; //set on pre-render - DeleteLink.Style.Add(HtmlTextWriterStyle.Color, "red"); - DeleteLink.Title = Current.Services.TextService.Localize("delete"); - DeleteLink.InnerText = Current.Services.TextService.Localize("delete"); - DeleteLink.Attributes.Add("class", "clear"); - - ButtonContainer.Controls.Add(DeleteLink); - ButtonContainer.Controls.Add(new LiteralControl(" ")); - ButtonContainer.Controls.Add(new LiteralControl(" ")); - if (!ShowDelete) - { - DeleteLink.Style.Add(HtmlTextWriterStyle.Display, "none"); - } - - RootContainer.Controls.Add(ButtonContainer); - - //add choose link with padding - ChooseLink = new HtmlAnchor(); - ChooseLink.HRef = "#"; //filled in on pre-render - ChooseLink.InnerText = Current.Services.TextService.Localize("choose") + "..."; - ChooseLink.Attributes.Add("data-section", this.TreePickerUrl); - ChooseLink.Attributes.Add("class", "choose"); - - RootContainer.Controls.Add(ChooseLink); - } - - /// - /// Registers the JavaScript required for the control to function and hides/shows controls depending on it's properties - /// - /// - protected override void OnPreRender(EventArgs e) - { - base.OnPreRender(e); - - //hide the buttons if no item, otherwise get the item title - if (string.IsNullOrEmpty(ItemIdValue.Value)) - { - ButtonContainer.Style.Add(HtmlTextWriterStyle.Display, "none"); - } - else - { - ItemTitle.InnerText = GetItemTitle(); - ItemTitle.Attributes.Add("title", GetItemBreadcrumbs()); // Adding full path/meta info (Issue U4-192) - } - /* - ChooseLink.HRef = string.Format("javascript:mc_{0}.LaunchPicker();", this.ClientID); - DeleteLink.HRef = string.Format("javascript:mc_{0}.ClearSelection();", this.ClientID); - */ - - RenderJSComponents(); - - /* - if (ScriptManager.GetCurrent(Page).IsInAsyncPostBack) - { - ScriptManager.RegisterStartupScript(this, this.GetType(), this.ClientID + "TreePicker", GetJSScript(), true); - } - else - { - Page.ClientScript.RegisterStartupScript(this.GetType(), this.ClientID + "TreePicker", GetJSScript(), true); - }*/ - - } - - - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs index d7ea239a3f..e5af44b747 100644 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs +++ b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs @@ -22,18 +22,10 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance return pack; } - public static InstalledPackage GetByGuid(string packageGuid) - { - InstalledPackage pack = new InstalledPackage(); - pack.Data = data.Package(packageGuid, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - return pack; - } - public static InstalledPackage MakeNew(string name) { InstalledPackage pack = new InstalledPackage(); pack.Data = data.MakeNew(name, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - pack.OnNew(EventArgs.Empty); return pack; } @@ -43,9 +35,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance _saveHitCount++; Current.Logger.Info("The InstalledPackage class save method has been hit {Total} times.", _saveHitCount); #endif - this.FireBeforeSave(EventArgs.Empty); data.Save(this.Data, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - this.FireAfterSave(EventArgs.Empty); } public static List GetAllInstalledPackages() @@ -63,12 +53,7 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance return val; } - private Core.Models.Packaging.PackageDefinition m_data; - public Core.Models.Packaging.PackageDefinition Data - { - get { return m_data; } - set { m_data = value; } - } + public Core.Models.Packaging.PackageDefinition Data { get; set; } public void Delete(int userId) { @@ -78,69 +63,9 @@ namespace Umbraco.Web._Legacy.Packager.PackageInstance public void Delete() { - this.FireBeforeDelete(EventArgs.Empty); data.Delete(this.Data.Id, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - this.FireAfterDelete(EventArgs.Empty); } - public static bool isPackageInstalled(string packageGuid) - { - try - { - if (data.GetFromGuid(packageGuid, IOHelper.MapPath(Settings.InstalledPackagesSettings), true) == null) - return false; - else - return true; - } - catch (Exception ex) - { - Current.Logger.Error(ex, "An error occured in isPackagedInstalled"); - return false; - } - } - - //EVENTS - public delegate void SaveEventHandler(InstalledPackage sender, EventArgs e); - public delegate void NewEventHandler(InstalledPackage sender, EventArgs e); - public delegate void DeleteEventHandler(InstalledPackage sender, EventArgs e); - - /// - /// Occurs when a macro is saved. - /// - public static event SaveEventHandler BeforeSave; - protected virtual void FireBeforeSave(EventArgs e) - { - if (BeforeSave != null) - BeforeSave(this, e); - } - - public static event SaveEventHandler AfterSave; - protected virtual void FireAfterSave(EventArgs e) - { - if (AfterSave != null) - AfterSave(this, e); - } - - public static event NewEventHandler New; - protected virtual void OnNew(EventArgs e) - { - if (New != null) - New(this, e); - } - - public static event DeleteEventHandler BeforeDelete; - protected virtual void FireBeforeDelete(EventArgs e) - { - if (BeforeDelete != null) - BeforeDelete(this, e); - } - - public static event DeleteEventHandler AfterDelete; - protected virtual void FireAfterDelete(EventArgs e) - { - if (AfterDelete != null) - AfterDelete(this, e); - } /// diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentPicker.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentPicker.cs deleted file mode 100644 index 018c49a249..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentPicker.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using Umbraco.Web._Legacy.Controls; -using Umbraco.Core; -using Umbraco.Core.Services; -using Umbraco.Web; -using Umbraco.Web.Composing; - -namespace umbraco.controls -{ - - public class ContentPicker : BaseTreePicker - { - - public ContentPicker() - { - AppAlias = Constants.Applications.Content; - TreeAlias = "content"; - } - - - public string AppAlias { get; set; } - public string TreeAlias { get; set; } - - public override string TreePickerUrl - { - get - { - return AppAlias; - } - } - - public override string ModalWindowTitle - { - get - { - return Current.Services.TextService.Localize("general/choose") + " " + Current.Services.TextService.Localize("sections/" + TreeAlias.ToLower()); - } - } - - protected override string GetItemTitle() - { - string tempTitle = ""; - try - { - if (Value != "" && Value != "-1") - { - //tempTitle = new cms.businesslogic.CMSNode(int.Parse(Value)).Text; - tempTitle = Current.Services.EntityService.Get(int.Parse(Value)).Name; - } - else - { - tempTitle = (!string.IsNullOrEmpty(TreeAlias) ? Current.Services.TextService.Localize(TreeAlias) : Current.Services.TextService.Localize(AppAlias)); - - } - } - catch { } - return tempTitle; - } - } -} From c89b50f0b82063e459d60ed08c664f6911ea8786 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 11 Jan 2019 14:30:04 +1100 Subject: [PATCH 070/223] large refactor/cleanup of most of the old package installer logic dealing with persisting the installedPackages.config which is now in the services, creates new parsers and removes a ton of old code, changes fetching packages to be async, uses XElement instead of old XmlNode apis, next we need to do the actual package installer updates --- .../Composing/Composers/ServicesComposer.cs | 19 +- .../Events/ImportPackageEventArgs.cs | 6 +- .../Events/UninstallPackageEventArgs.cs | 8 +- .../Models/Packaging/CompiledPackage.cs | 48 +++ .../Models/Packaging/IPackageInfo.cs | 19 + .../Models/Packaging/InstallationSummary.cs | 65 ++- .../InstallationSummaryExtentions.cs | 23 -- src/Umbraco.Core/Models/Packaging/MetaData.cs | 23 -- .../Models/Packaging/PackageDefinition.cs | 6 +- .../Packaging/RequirementsType.cs | 2 +- .../Models/Packaging/UninstallationSummary.cs | 21 +- .../UninstallationSummaryExtentions.cs | 22 -- .../Packaging/ICreatedPackagesRepository.cs | 5 +- .../Packaging/IInstalledPackagesRepository.cs | 9 +- .../Packaging/IPackageExtraction.cs | 2 +- .../Packaging/IPackageInstallation.cs | 3 +- .../Packaging/PackageActionRunner.cs | 6 +- .../Packaging/PackageBinaryInspector.cs | 295 -------------- .../Packaging/PackageDefinitionXmlParser.cs | 165 ++++++++ .../Packaging/PackageInstallation.cs | 28 +- ...gesRepository.cs => PackagesRepository.cs} | 153 +++---- .../Services/IPackagingService.cs | 19 +- .../Services/Implement/PackagingService.cs | 199 ++++------ src/Umbraco.Core/Umbraco.Core.csproj | 12 +- src/Umbraco.Core/Xml/XmlHelper.cs | 165 +------- .../_Legacy/PackageActions/IPackageAction.cs | 6 +- .../Composing/PackageActionCollectionTests.cs | 9 +- .../CreatedPackagesRepositoryTests.cs | 3 +- .../Services/PackagingServiceTests.cs | 2 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 8 +- src/Umbraco.Web/Editors/PackageController.cs | 2 +- .../Editors/PackageInstallController.cs | 122 +++--- .../Controllers/InstallPackageController.cs | 18 +- .../InstallSteps/ConfigureMachineKey.cs | 5 +- .../InstallSteps/DatabaseConfigureStep.cs | 5 +- .../InstallSteps/DatabaseInstallStep.cs | 7 +- .../InstallSteps/DatabaseUpgradeStep.cs | 5 +- .../InstallSteps/FilePermissionsStep.cs | 5 +- .../Install/InstallSteps/NewInstallStep.cs | 5 +- .../InstallSteps/SetUmbracoVersionStep.cs | 7 +- .../InstallSteps/StarterKitCleanupStep.cs | 5 +- .../InstallSteps/StarterKitDownloadStep.cs | 24 +- .../InstallSteps/StarterKitInstallStep.cs | 5 +- .../Install/InstallSteps/UpgradeStep.cs | 3 +- .../Install/Models/InstallSetupStep.cs | 14 +- .../Models/LocalPackageInstallModel.cs | 3 - src/Umbraco.Web/Umbraco.Web.csproj | 5 - .../_Legacy/PackageActions/PackageHelper.cs | 84 ---- .../_Legacy/PackageActions/addApplication.cs | 20 +- .../PackageActions/addDashboardSection.cs | 44 +-- .../PackageActions/addProxyFeedHost.cs | 81 ++-- .../PackageActions/addStringToHtmlElement.cs | 202 ---------- .../_Legacy/PackageActions/allowDoctype.cs | 17 +- .../PackageActions/publishRootDocument.cs | 16 +- .../removeStringFromTemplate.cs | 34 -- src/Umbraco.Web/_Legacy/Packager/Installer.cs | 247 +++++------- .../PackageInstance/InstalledPackage.cs | 136 ------- src/Umbraco.Web/_Legacy/Packager/data.cs | 374 ------------------ 58 files changed, 810 insertions(+), 2036 deletions(-) create mode 100644 src/Umbraco.Core/Models/Packaging/CompiledPackage.cs create mode 100644 src/Umbraco.Core/Models/Packaging/IPackageInfo.cs delete mode 100644 src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs delete mode 100644 src/Umbraco.Core/Models/Packaging/MetaData.cs rename src/Umbraco.Core/{ => Models}/Packaging/RequirementsType.cs (65%) delete mode 100644 src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs delete mode 100644 src/Umbraco.Core/Packaging/PackageBinaryInspector.cs create mode 100644 src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs rename src/Umbraco.Core/Packaging/{CreatedPackagesRepository.cs => PackagesRepository.cs} (79%) delete mode 100644 src/Umbraco.Web/_Legacy/PackageActions/PackageHelper.cs delete mode 100644 src/Umbraco.Web/_Legacy/PackageActions/addStringToHtmlElement.cs delete mode 100644 src/Umbraco.Web/_Legacy/PackageActions/removeStringFromTemplate.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/data.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 9692a2d87c..98f239de3b 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -60,11 +60,9 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(); composition.RegisterUnique(); - composition.RegisterUnique(factory => - new CreatedPackagesRepository( //we are using a factory because there are optional ctor args - factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), factory.GetInstance())); + + composition.RegisterUnique(factory => CreatePackageRepository(factory, "createdPackages.config")); + composition.RegisterUnique(factory => CreatePackageRepository(factory, "installedPackages.config")); //TODO: These are replaced in the web project - we need to declare them so that // something is wired up, just not sure this is very nice but will work for now. @@ -74,6 +72,17 @@ namespace Umbraco.Core.Composing.Composers return composition; } + /// + /// Creates an instance of PackagesRepository for either the ICreatedPackagesRepository or the IInstalledPackagesRepository + /// + /// + /// + /// + private static PackagesRepository CreatePackageRepository(IFactory factory, string packageRepoFileName) + => new PackagesRepository( + factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), + packageRepoFileName); + private static LocalizedTextServiceFileSources SourcesFactory(IFactory container) { var mainLangFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Umbraco + "/config/lang/")); diff --git a/src/Umbraco.Core/Events/ImportPackageEventArgs.cs b/src/Umbraco.Core/Events/ImportPackageEventArgs.cs index ba356ff952..61369af59d 100644 --- a/src/Umbraco.Core/Events/ImportPackageEventArgs.cs +++ b/src/Umbraco.Core/Events/ImportPackageEventArgs.cs @@ -7,19 +7,19 @@ namespace Umbraco.Core.Events { public class ImportPackageEventArgs : CancellableEnumerableObjectEventArgs, IEquatable> { - public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData, bool canCancel) + public ImportPackageEventArgs(TEntity eventObject, IPackageInfo packageMetaData, bool canCancel) : base(new[] { eventObject }, canCancel) { PackageMetaData = packageMetaData ?? throw new ArgumentNullException(nameof(packageMetaData)); } - public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData) + public ImportPackageEventArgs(TEntity eventObject, IPackageInfo packageMetaData) : this(eventObject, packageMetaData, true) { } - public MetaData PackageMetaData { get; } + public IPackageInfo PackageMetaData { get; } public IEnumerable InstallationSummary => EventObject; diff --git a/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs b/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs index 13c260bf3e..2618d04e17 100644 --- a/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs +++ b/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs @@ -5,17 +5,13 @@ namespace Umbraco.Core.Events { public class UninstallPackageEventArgs : CancellableObjectEventArgs> { - public UninstallPackageEventArgs(TEntity eventObject, bool canCancel) + public UninstallPackageEventArgs(TEntity eventObject, IPackageInfo packageMetaData, bool canCancel) : base(new[] { eventObject }, canCancel) - { } - - public UninstallPackageEventArgs(TEntity eventObject, MetaData packageMetaData) - : base(new[] { eventObject }) { PackageMetaData = packageMetaData; } - public MetaData PackageMetaData { get; } + public IPackageInfo PackageMetaData { get; } public IEnumerable UninstallationSummary => EventObject; } diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs new file mode 100644 index 0000000000..cb3fbd7eee --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Umbraco.Core.Models.Packaging +{ + /// + /// The model of the package definition within an umbraco (zip) package file + /// + public class CompiledPackage : IPackageInfo + { + public string Name { get; set; } + + public string Version { get; set; } + + public string Url { get; set; } + + public string License { get; set; } + + public string LicenseUrl { get; set; } + + public Version UmbracoVersion { get; set; } + + public RequirementsType UmbracoVersionRequirementsType { get; set; } + + public string Author { get; set; } + + public string AuthorUrl { get; set; } + + public string Readme { get; set; } + + public string Control { get; set; } + + public string IconUrl { get; set; } + + public List Files { get; set; } = new List(); + + } + + public class CompiledPackageFile + { + public string OriginalPath { get; set; } + public string UniqueFileName { get; set; } + public string OriginalName { get; set; } + } + + +} diff --git a/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs b/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs new file mode 100644 index 0000000000..8722ee7811 --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs @@ -0,0 +1,19 @@ +using System; + +namespace Umbraco.Core.Models.Packaging +{ + public interface IPackageInfo + { + string Name { get; } + string Version { get; } + string Url { get; } + string License { get; } + string LicenseUrl { get; } + Version UmbracoVersion { get; } + string Author { get; } + string AuthorUrl { get; } + string Readme { get; } + string Control { get; } //fixme - this needs to be an angular view + string IconUrl { get; } + } +} diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index 39df529300..ddecf53653 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.Serialization; +using Umbraco.Core.IO; +using Umbraco.Core.Services; namespace Umbraco.Core.Models.Packaging { @@ -8,17 +11,57 @@ namespace Umbraco.Core.Models.Packaging [DataContract(IsReference = true)] public class InstallationSummary { - public MetaData MetaData { get; set; } - public IEnumerable DataTypesInstalled { get; set; } - public IEnumerable LanguagesInstalled { get; set; } - public IEnumerable DictionaryItemsInstalled { get; set; } - public IEnumerable MacrosInstalled { get; set; } - public IEnumerable FilesInstalled { get; set; } - public IEnumerable TemplatesInstalled { get; set; } - public IEnumerable ContentTypesInstalled { get; set; } - public IEnumerable StylesheetsInstalled { get; set; } - public IEnumerable ContentInstalled { get; set; } - public IEnumerable Actions { get; set; } + public IPackageInfo MetaData { get; set; } + public IEnumerable DataTypesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable LanguagesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable DictionaryItemsInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable MacrosInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable FilesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable TemplatesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable ContentTypesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable StylesheetsInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable Actions { get; set; } = Enumerable.Empty(); public bool PackageInstalled { get; set; } + + public static InstallationSummary FromPackageDefinition(PackageDefinition def, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService) + { + var macros = TryGetIntegerIds(def.Macros).Select(macroService.GetById).ToList(); + var templates = TryGetIntegerIds(def.Templates).Select(fileService.GetTemplate).ToList(); + var contentTypes = TryGetIntegerIds(def.DocumentTypes).Select(contentTypeService.Get).ToList(); // fixme - media types? + var dataTypes = TryGetIntegerIds(def.DataTypes).Select(dataTypeService.GetDataType).ToList(); + var dictionaryItems = TryGetIntegerIds(def.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList(); + var languages = TryGetIntegerIds(def.Languages).Select(localizationService.GetLanguageById).ToList(); + + for (var i = 0; i < def.Files.Count; i++) + { + var filePath = def.Files[i]; + def.Files[i] = filePath.GetRelativePath(); + } + + return new InstallationSummary + { + ContentTypesInstalled = contentTypes, + DataTypesInstalled = dataTypes, + DictionaryItemsInstalled = dictionaryItems, + FilesInstalled = def.Files, + LanguagesInstalled = languages, + MacrosInstalled = macros, + MetaData = def, + TemplatesInstalled = templates, + }; + } + + private static IEnumerable TryGetIntegerIds(IEnumerable ids) + { + var intIds = new List(); + foreach (var id in ids) + { + if (int.TryParse(id, out var parsed)) + intIds.Add(parsed); + } + return intIds; + } } + } diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs deleted file mode 100644 index 3b969d84dc..0000000000 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummaryExtentions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Models.Packaging -{ - internal static class InstallationSummaryExtentions - { - public static InstallationSummary InitEmpty(this InstallationSummary summary) - { - summary.Actions = new List(); - summary.ContentInstalled = new List(); - summary.ContentTypesInstalled = new List(); - summary.DataTypesInstalled = new List(); - summary.DictionaryItemsInstalled = new List(); - summary.FilesInstalled = new List(); - summary.LanguagesInstalled = new List(); - summary.MacrosInstalled = new List(); - summary.MetaData = new MetaData(); - summary.TemplatesInstalled = new List(); - summary.PackageInstalled = false; - return summary; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Packaging/MetaData.cs b/src/Umbraco.Core/Models/Packaging/MetaData.cs deleted file mode 100644 index a1cb450c5b..0000000000 --- a/src/Umbraco.Core/Models/Packaging/MetaData.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Umbraco.Core.Models.Packaging -{ - [Serializable] - [DataContract(IsReference = true)] - public class MetaData - { - public string Name { get; set; } - public string Version { get; set; } - public string Url { get; set; } - public string License { get; set; } - public string LicenseUrl { get; set; } - public int ReqMajor { get; set; } - public int ReqMinor { get; set; } - public int ReqPatch { get; set; } - public string AuthorName { get; set; } - public string AuthorUrl { get; set; } - public string Readme { get; set; } - public string Control { get; set; } - } -} diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index 01d10fa2e1..65e26419f0 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -7,7 +7,7 @@ using System.Runtime.Serialization; namespace Umbraco.Core.Models.Packaging { [DataContract(Name = "packageInstance")] - public class PackageDefinition + public class PackageDefinition : IPackageInfo { [DataMember(Name = "id")] public int Id { get; set; } @@ -89,9 +89,9 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "files")] public IList Files { get; set; } = new List(); - //TODO: Change this to angular view + //fixme: Change this to angular view [DataMember(Name = "loadControl")] - public string LoadControl { get; set; } = string.Empty; + public string Control { get; set; } = string.Empty; [DataMember(Name = "actions")] public string Actions { get; set; } = ""; diff --git a/src/Umbraco.Core/Packaging/RequirementsType.cs b/src/Umbraco.Core/Models/Packaging/RequirementsType.cs similarity index 65% rename from src/Umbraco.Core/Packaging/RequirementsType.cs rename to src/Umbraco.Core/Models/Packaging/RequirementsType.cs index 38cac482c2..2b6894ed0f 100644 --- a/src/Umbraco.Core/Packaging/RequirementsType.cs +++ b/src/Umbraco.Core/Models/Packaging/RequirementsType.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Packaging +namespace Umbraco.Core.Models.Packaging { public enum RequirementsType { diff --git a/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs index cfa454f91c..20cbedbcf0 100644 --- a/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.Serialization; namespace Umbraco.Core.Models.Packaging @@ -8,16 +9,16 @@ namespace Umbraco.Core.Models.Packaging [DataContract(IsReference = true)] public class UninstallationSummary { - public MetaData MetaData { get; set; } - public IEnumerable DataTypesUninstalled { get; set; } - public IEnumerable LanguagesUninstalled { get; set; } - public IEnumerable DictionaryItemsUninstalled { get; set; } - public IEnumerable MacrosUninstalled { get; set; } - public IEnumerable FilesUninstalled { get; set; } - public IEnumerable TemplatesUninstalled { get; set; } - public IEnumerable ContentTypesUninstalled { get; set; } - public IEnumerable StylesheetsUninstalled { get; set; } - public IEnumerable ContentUninstalled { get; set; } + public IPackageInfo MetaData { get; set; } + public IEnumerable DataTypesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable LanguagesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable DictionaryItemsUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable MacrosUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable FilesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable TemplatesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable ContentTypesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable StylesheetsUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable ContentUninstalled { get; set; } = Enumerable.Empty(); public bool PackageUninstalled { get; set; } } } diff --git a/src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs b/src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs deleted file mode 100644 index 688b78fa1f..0000000000 --- a/src/Umbraco.Core/Models/Packaging/UninstallationSummaryExtentions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Models.Packaging -{ - internal static class UninstallationSummaryExtentions - { - public static UninstallationSummary InitEmpty(this UninstallationSummary summary) - { - summary.ContentUninstalled = new List(); - summary.ContentTypesUninstalled = new List(); - summary.DataTypesUninstalled = new List(); - summary.DictionaryItemsUninstalled = new List(); - summary.FilesUninstalled = new List(); - summary.LanguagesUninstalled = new List(); - summary.MacrosUninstalled = new List(); - summary.MetaData = new MetaData(); - summary.TemplatesUninstalled = new List(); - summary.PackageUninstalled = false; - return summary; - } - } -} diff --git a/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs b/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs index 52a16ddff0..42606da6ef 100644 --- a/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/ICreatedPackagesRepository.cs @@ -2,6 +2,9 @@ namespace Umbraco.Core.Packaging { + /// + /// Manages the storage of created package definitions + /// public interface ICreatedPackagesRepository : IPackageDefinitionRepository { /// @@ -10,4 +13,4 @@ namespace Umbraco.Core.Packaging /// string ExportPackage(PackageDefinition definition); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs b/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs index 3d601d6b1d..61f611edc5 100644 --- a/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/IInstalledPackagesRepository.cs @@ -2,12 +2,9 @@ namespace Umbraco.Core.Packaging { - - //TODO: We need to figure out how we want to do this - // we have 2x repositories for saving created and installed packages - // created packages can also be exported - // maybe the below will work? - + /// + /// Manages the storage of installed package definitions + /// public interface IInstalledPackagesRepository : IPackageDefinitionRepository { } diff --git a/src/Umbraco.Core/Packaging/IPackageExtraction.cs b/src/Umbraco.Core/Packaging/IPackageExtraction.cs index 21a5198f55..02e98dc539 100644 --- a/src/Umbraco.Core/Packaging/IPackageExtraction.cs +++ b/src/Umbraco.Core/Packaging/IPackageExtraction.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Packaging { /// - /// Used to access an umbraco package file + /// Used to access an umbraco package (zip) file /// Remeber that filenames must be unique /// use "FindDubletFileNames" for sanitycheck /// diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 6dc4f0fd4e..e8950390e4 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -9,8 +9,7 @@ namespace Umbraco.Core.Packaging // there are app domain reboots involved so a single method cannot be used. This needs to either be split into several // methods or return an object with a callback to proceed to the next step. InstallationSummary InstallPackage(string packageFilePath, int userId); - MetaData GetMetaData(string packageFilePath); + IPackageInfo GetMetaData(string packageFilePath); PreInstallWarnings GetPreInstallWarnings(string packageFilePath); - XElement GetConfigXmlElement(string packageFilePath); } } diff --git a/src/Umbraco.Core/Packaging/PackageActionRunner.cs b/src/Umbraco.Core/Packaging/PackageActionRunner.cs index c7545bdae8..64b913989c 100644 --- a/src/Umbraco.Core/Packaging/PackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/PackageActionRunner.cs @@ -1,5 +1,5 @@ using System; -using System.Xml; +using System.Xml.Linq; using Umbraco.Core.Logging; using Umbraco.Core._Legacy.PackageActions; @@ -26,7 +26,7 @@ namespace Umbraco.Core.Packaging /// Name of the package. /// The action alias. /// The action XML. - public void RunPackageAction(string packageName, string actionAlias, XmlNode actionXml) + public void RunPackageAction(string packageName, string actionAlias, XElement actionXml) { foreach (var ipa in _packageActions) @@ -49,7 +49,7 @@ namespace Umbraco.Core.Packaging /// Name of the package. /// The action alias. /// The action XML. - public void UndoPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) + public void UndoPackageAction(string packageName, string actionAlias, XElement actionXml) { foreach (var ipa in _packageActions) { diff --git a/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs b/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs deleted file mode 100644 index 7cacb30bd3..0000000000 --- a/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs +++ /dev/null @@ -1,295 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Security; -using System.Security.Permissions; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; - -namespace Umbraco.Core.Packaging -{ - // Note - // That class uses ReflectionOnlyLoad which does NOT handle policies (bindingRedirect) and - // therefore raised warnings when installing a package, if an exact dependency could not be - // found, though it would be found via policies. So we have to explicitely apply policies - // where appropriate. - - internal class PackageBinaryInspector : MarshalByRefObject - { - /// - /// Entry point to call from your code - /// - /// - /// - /// - /// - /// - /// Will perform the assembly scan in a separate app domain - /// - public static IEnumerable ScanAssembliesForTypeReference(IEnumerable assemblys, out string[] errorReport) - { - // need to wrap in a safe call context in order to prevent whatever Umbraco stores - // in the logical call context from flowing to the created app domain (eg, the - // UmbracoDatabase is *not* serializable and cannot and should not flow). - using (new SafeCallContext()) - { - var appDomain = GetTempAppDomain(); - var type = typeof(PackageBinaryInspector); - try - { - var value = (PackageBinaryInspector)appDomain.CreateInstanceAndUnwrap( - type.Assembly.FullName, - type.FullName); - // do NOT turn PerformScan into static (even if ReSharper says so)! - var result = value.PerformScan(assemblys.ToArray(), out errorReport); - return result; - } - finally - { - AppDomain.Unload(appDomain); - } - } - } - - /// - /// Entry point to call from your code - /// - /// - /// - /// - /// - /// - /// Will perform the assembly scan in a separate app domain - /// - public static IEnumerable ScanAssembliesForTypeReference(string dllPath, out string[] errorReport) - { - var appDomain = GetTempAppDomain(); - var type = typeof(PackageBinaryInspector); - try - { - var value = (PackageBinaryInspector)appDomain.CreateInstanceAndUnwrap( - type.Assembly.FullName, - type.FullName); - // do NOT turn PerformScan into static (even if ReSharper says so)! - var result = value.PerformScan(dllPath, out errorReport); - return result; - } - finally - { - AppDomain.Unload(appDomain); - } - } - - /// - /// Performs the assembly scanning - /// - /// - /// - /// - /// - /// - /// This method is executed in a separate app domain - /// - private IEnumerable PerformScan(IEnumerable assemblies, out string[] errorReport) - { - //we need this handler to resolve assembly dependencies when loading below - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) => - { - var name = AppDomain.CurrentDomain.ApplyPolicy(e.Name); - var a = Assembly.ReflectionOnlyLoad(name); - if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name); - return a; - }; - - //First load each dll file into the context - // do NOT apply policy here: we want to scan the dlls that are in the binaries - var loaded = assemblies.Select(Assembly.ReflectionOnlyLoad).ToList(); - - //scan - return PerformScan(loaded, out errorReport); - } - - /// - /// Performs the assembly scanning - /// - /// - /// - /// - /// - /// - /// This method is executed in a separate app domain - /// - private IEnumerable PerformScan(string dllPath, out string[] errorReport) - { - if (Directory.Exists(dllPath) == false) - { - throw new DirectoryNotFoundException("Could not find directory " + dllPath); - } - - //we need this handler to resolve assembly dependencies when loading below - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) => - { - var name = AppDomain.CurrentDomain.ApplyPolicy(e.Name); - var a = Assembly.ReflectionOnlyLoad(name); - if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name); - return a; - }; - - //First load each dll file into the context - // do NOT apply policy here: we want to scan the dlls that are in the path - var files = Directory.GetFiles(dllPath, "*.dll"); - var loaded = files.Select(Assembly.ReflectionOnlyLoadFrom).ToList(); - - //scan - return PerformScan(loaded, out errorReport); - } - - private static IEnumerable PerformScan(IList loaded, out string[] errorReport) - { - var dllsWithReference = new List(); - var errors = new List(); - var assembliesWithErrors = new List(); - - //load each of the LoadFrom assemblies into the Load context too - foreach (var a in loaded) - { - var name = AppDomain.CurrentDomain.ApplyPolicy(a.FullName); - Assembly.ReflectionOnlyLoad(name); - } - - //get the list of assembly names to compare below - var loadedNames = loaded.Select(x => x.GetName().Name).ToArray(); - - //Then load each referenced assembly into the context - foreach (var a in loaded) - { - //don't load any referenced assemblies that are already found in the loaded array - this is based on name - // regardless of version. We'll assume that if the assembly found in the folder matches the assembly name - // being looked for, that is the version the user has shipped their package with and therefore it 'must' be correct - foreach (var assemblyName in a.GetReferencedAssemblies().Where(ass => loadedNames.Contains(ass.Name) == false)) - { - try - { - var name = AppDomain.CurrentDomain.ApplyPolicy(assemblyName.FullName); - Assembly.ReflectionOnlyLoad(name); - } - catch (FileNotFoundException) - { - //if an exception occurs it means that a referenced assembly could not be found - errors.Add( - string.Concat("This package references the assembly '", - assemblyName.Name, - "' which was not found")); - assembliesWithErrors.Add(a); - } - catch (Exception ex) - { - //if an exception occurs it means that a referenced assembly could not be found - errors.Add( - string.Concat("This package could not be verified for compatibility. An error occurred while loading a referenced assembly '", - assemblyName.Name, - "' see error log for full details.")); - assembliesWithErrors.Add(a); - Current.Logger.Error(ex, "An error occurred scanning package assembly '{AssemblyName}'", assemblyName.FullName); - } - } - } - - var contractType = GetLoadFromContractType(); - - //now that we have all referenced types into the context we can look up stuff - foreach (var a in loaded.Except(assembliesWithErrors)) - { - //now we need to see if they contain any type 'T' - var reflectedAssembly = a; - - try - { - var found = reflectedAssembly.GetExportedTypes() - .Where(contractType.IsAssignableFrom); - - if (found.Any()) - { - dllsWithReference.Add(reflectedAssembly.FullName); - } - } - catch (Exception ex) - { - //This is a hack that nobody can seem to get around, I've read everything and it seems that - // this is quite a common thing when loading types into reflection only load context, so - // we're just going to ignore this specific one for now - var typeLoadEx = ex as TypeLoadException; - if (typeLoadEx != null) - { - if (typeLoadEx.Message.InvariantContains("does not have an implementation")) - { - //ignore - continue; - } - } - else - { - errors.Add( - string.Concat("This package could not be verified for compatibility. An error occurred while scanning a packaged assembly '", - a.GetName().Name, - "' see error log for full details.")); - assembliesWithErrors.Add(a); - Current.Logger.Error(ex, "An error occurred scanning package assembly '{AssemblyName}'", a.GetName().FullName); - } - } - - } - - errorReport = errors.ToArray(); - return dllsWithReference; - } - - /// - /// In order to compare types, the types must be in the same context, this method will return the type that - /// we are checking against but from the Load context. - /// - /// - /// - private static Type GetLoadFromContractType() - { - var name = AppDomain.CurrentDomain.ApplyPolicy(typeof(T).Assembly.FullName); - var contractAssemblyLoadFrom = Assembly.ReflectionOnlyLoad(name); - - var contractType = contractAssemblyLoadFrom.GetExportedTypes() - .FirstOrDefault(x => x.FullName == typeof(T).FullName && x.Assembly.FullName == typeof(T).Assembly.FullName); - - if (contractType == null) - { - throw new InvalidOperationException("Could not find type " + typeof(T) + " in the LoadFrom assemblies"); - } - return contractType; - } - - /// - /// Create an app domain - /// - /// - private static AppDomain GetTempAppDomain() - { - //copy the current app domain setup but don't shadow copy files - var appName = "TempDomain" + Guid.NewGuid(); - var domainSetup = new AppDomainSetup - { - ApplicationName = appName, - ShadowCopyFiles = "false", - ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase, - ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, - DynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase, - LicenseFile = AppDomain.CurrentDomain.SetupInformation.LicenseFile, - LoaderOptimization = AppDomain.CurrentDomain.SetupInformation.LoaderOptimization, - PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, - PrivateBinPathProbe = AppDomain.CurrentDomain.SetupInformation.PrivateBinPathProbe - }; - - // create new domain with full trust - return AppDomain.CreateDomain(appName, AppDomain.CurrentDomain.Evidence, domainSetup, new PermissionSet(PermissionState.Unrestricted)); - } - } -} diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs new file mode 100644 index 0000000000..6f3e4a3603 --- /dev/null +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Packaging; + +namespace Umbraco.Core.Packaging +{ + /// + /// Parses the xml document contained in a compiled (zip) Umbraco package + /// + public class CompiledPackageXmlParser + { + public CompiledPackageXmlParser() + { + + } + + public CompiledPackage ToCompiledPackage(XDocument xml) + { + if (xml == null) throw new ArgumentNullException(nameof(xml)); + if (xml.Root == null) throw new ArgumentException(nameof(xml), "The xml document is invalid"); + if (xml.Root.Name != Constants.Packaging.UmbPackageNodeName) throw new FormatException("The xml document is invalid"); + + var info = xml.Root.Element("info"); + if (info == null) throw new FormatException("The xml document is invalid"); + var package = xml.Element("package"); + if (package == null) throw new FormatException("The xml document is invalid"); + var author = package.Element("author"); + if (author == null) throw new FormatException("The xml document is invalid"); + var requirements = package.Element("requirements"); + if (requirements == null) throw new FormatException("The xml document is invalid"); + + var def = new CompiledPackage + { + Name = package.Element("name")?.Value, + Author = author.Element("name")?.Value, + AuthorUrl = author.Element("website")?.Value, + Version = package.Element("version")?.Value, + Readme = info.Element("readme")?.Value, + License = package.Element("license")?.Value, + LicenseUrl = package.Element("license")?.AttributeValue("url"), + Url = package.Element("url")?.Value, + IconUrl = package.Element("iconUrl")?.Value, + UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), + UmbracoVersionRequirementsType = Enum.Parse(requirements.AttributeValue("type")), + Control = package.Element("control")?.Value, + + Files = xml.Root.Element("files")?.Elements("files")?.Select(x => new CompiledPackageFile + { + UniqueFileName = x.Element("guid")?.Value, + OriginalName = x.Element("orgPath")?.Value, + OriginalPath = x.Element("orgName")?.Value + }).ToList() ?? new List(), + + }; + + return def; + } + + } + + /// + /// Converts a to and from XML + /// + public class PackageDefinitionXmlParser + { + private readonly ILogger _logger; + + public PackageDefinitionXmlParser(ILogger logger) + { + _logger = logger; + } + + public PackageDefinition ToPackageDefinition(XElement xml) + { + if (xml == null) return null; + + var retVal = new PackageDefinition + { + Id = xml.AttributeValue("id"), + Name = xml.AttributeValue("name") ?? string.Empty, + FolderId = xml.AttributeValue("folder"), + PackagePath = xml.AttributeValue("packagePath") ?? string.Empty, + Version = xml.AttributeValue("version") ?? string.Empty, + Url = xml.AttributeValue("url") ?? string.Empty, + PackageId = xml.AttributeValue("packageGuid"), + IconUrl = xml.AttributeValue("iconUrl") ?? string.Empty, + UmbracoVersion = xml.AttributeValue("umbVersion"), + License = xml.Element("license")?.Value ?? string.Empty, + LicenseUrl = xml.Element("license")?.AttributeValue("url") ?? string.Empty, + Author = xml.Element("author")?.Value ?? string.Empty, + AuthorUrl = xml.Element("author")?.AttributeValue("url") ?? string.Empty, + Readme = xml.Element("readme")?.Value ?? string.Empty, + Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value + ContentNodeId = xml.Element("content")?.AttributeValue("nodeId") ?? string.Empty, + ContentLoadChildNodes = xml.Element("content")?.AttributeValue("loadChildNodes") ?? false, + Macros = xml.Element("macros")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Templates = xml.Element("templates")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Stylesheets = xml.Element("stylesheets")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + DocumentTypes = xml.Element("documentTypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Languages = xml.Element("languages")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + DataTypes = xml.Element("datatypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + Files = xml.Element("files")?.Elements("file").Select(x => x.Value).ToList() ?? new List(), + Control = xml.Element("loadcontrol")?.Value ?? string.Empty + }; + + return retVal; + } + + public XElement ToXml(PackageDefinition def) + { + var actionsXml = new XElement("actions"); + try + { + actionsXml = XElement.Parse(def.Actions); + } + catch (Exception e) + { + _logger.Warn(e, "Could not add package actions to the package xml definition, the xml did not parse"); + } + + var packageXml = new XElement("package", + new XAttribute("id", def.Id), + new XAttribute("version", def.Version ?? string.Empty), + new XAttribute("url", def.Url ?? string.Empty), + new XAttribute("name", def.Name ?? string.Empty), + new XAttribute("folder", def.FolderId), + new XAttribute("packagePath", def.PackagePath ?? string.Empty), + new XAttribute("iconUrl", def.IconUrl ?? string.Empty), + new XAttribute("umbVersion", def.UmbracoVersion), + new XAttribute("packageGuid", def.PackageId), + + new XElement("license", + new XCData(def.License ?? string.Empty), + new XAttribute("url", def.LicenseUrl ?? string.Empty)), + + new XElement("author", + new XCData(def.Author ?? string.Empty), + new XAttribute("url", def.AuthorUrl ?? string.Empty)), + + new XElement("readme", new XCData(def.Readme ?? string.Empty)), + actionsXml, + new XElement("datatypes", string.Join(",", def.DataTypes ?? Array.Empty())), + + new XElement("content", + new XAttribute("nodeId", def.ContentNodeId), + new XAttribute("loadChildNodes", def.ContentLoadChildNodes)), + + new XElement("templates", string.Join(",", def.Templates ?? Array.Empty())), + new XElement("stylesheets", string.Join(",", def.Stylesheets ?? Array.Empty())), + new XElement("documentTypes", string.Join(",", def.DocumentTypes ?? Array.Empty())), + new XElement("macros", string.Join(",", def.Macros ?? Array.Empty())), + new XElement("files", (def.Files ?? Array.Empty()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))), + new XElement("languages", string.Join(",", def.Languages ?? Array.Empty())), + new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty())), + new XElement("loadcontrol", def.Control ?? string.Empty)); //fixme: no more loadcontrol, needs to be an angular view + + return packageXml; + } + } +} diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 556c5203ec..6c9cd57451 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -78,7 +78,7 @@ namespace Umbraco.Core.Packaging } } - public MetaData GetMetaData(string packageFilePath) + public IPackageInfo GetMetaData(string packageFilePath) { try { @@ -117,14 +117,14 @@ namespace Umbraco.Core.Packaging XElement documentSet; XElement documents; XElement actions; - MetaData metaData; + IPackageInfo metaData; InstallationSummary installationSummary; try { XElement rootElement = GetConfigXmlElement(packageFile); PackageSupportedCheck(rootElement); - PackageStructureSanetyCheck(packageFile, rootElement); + PackageStructureSanityCheck(packageFile, rootElement); dataTypes = rootElement.Element(Constants.Packaging.DataTypesNodeName); languages = rootElement.Element(Constants.Packaging.LanguagesNodeName); dictionaryItems = rootElement.Element(Constants.Packaging.DictionaryItemsNodeName); @@ -220,7 +220,7 @@ namespace Umbraco.Core.Packaging public XElement GetConfigXmlElement(string packageFilePath) { - XDocument document = GetConfigXmlDoc(packageFilePath); + var document = GetConfigXmlDoc(packageFilePath); if (document.Root == null || document.Root.Name.LocalName.Equals(Constants.Packaging.UmbPackageNodeName) == false) { @@ -229,13 +229,7 @@ namespace Umbraco.Core.Packaging return document.Root; } - internal void PackageStructureSanetyCheck(string packageFilePath) - { - XElement rootElement = GetConfigXmlElement(packageFilePath); - PackageStructureSanetyCheck(packageFilePath, rootElement); - } - - private void PackageStructureSanetyCheck(string packageFilePath, XElement rootElement) + private void PackageStructureSanityCheck(string packageFilePath, XElement rootElement) { XElement filesElement = rootElement.Element(Constants.Packaging.FilesNodeName); if (filesElement != null) @@ -513,7 +507,7 @@ namespace Umbraco.Core.Packaging return pathElement.TrimStart(new[] {'\\', '/', '~'}).Replace("/", "\\"); } - private MetaData GetMetaData(XElement xRootElement) + private IPackageInfo GetMetaData(XElement xRootElement) { XElement infoElement = xRootElement.Element(Constants.Packaging.InfoNodeName); @@ -535,21 +529,19 @@ namespace Umbraco.Core.Packaging var readmeElement = infoElement.XPathSelectElement(Constants.Packaging.ReadmeXpath); XElement controlElement = xRootElement.Element(Constants.Packaging.ControlNodeName); - - return new MetaData + + return new PackageDefinition { Name = StringValue(nameElement), Version = StringValue(versionElement), Url = StringValue(urlElement), License = StringValue(licenseElement), LicenseUrl = StringAttribute(licenseElement, Constants.Packaging.PackageLicenseXpathUrlAttribute), - AuthorName = StringValue(authorNameElement), + Author = StringValue(authorNameElement), AuthorUrl = StringValue(authorUrlElement), Readme = StringValue(readmeElement), Control = StringValue(controlElement), - ReqMajor = IntValue(majorElement), - ReqMinor = IntValue(minorElement), - ReqPatch = IntValue(patchElement) + UmbracoVersion = new Version(IntValue(majorElement), IntValue(minorElement), IntValue(patchElement)) }; } diff --git a/src/Umbraco.Core/Packaging/CreatedPackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs similarity index 79% rename from src/Umbraco.Core/Packaging/CreatedPackagesRepository.cs rename to src/Umbraco.Core/Packaging/PackagesRepository.cs index 169b161fbc..9f37f8a546 100644 --- a/src/Umbraco.Core/Packaging/CreatedPackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -15,7 +15,10 @@ using File = System.IO.File; namespace Umbraco.Core.Packaging { - internal class CreatedPackagesRepository : ICreatedPackagesRepository + /// + /// Manages the storage of installed/created package definitions + /// + internal class PackagesRepository : ICreatedPackagesRepository, IInstalledPackagesRepository { private readonly IContentService _contentService; private readonly IContentTypeService _contentTypeService; @@ -25,16 +28,37 @@ namespace Umbraco.Core.Packaging private readonly ILocalizationService _languageService; private readonly IEntityXmlSerializer _serializer; private readonly ILogger _logger; + private readonly string _packageRepositoryFileName; private readonly string _mediaFolderPath; private readonly string _packagesFolderPath; private readonly string _tempFolderPath; - - public CreatedPackagesRepository(IContentService contentService, IContentTypeService contentTypeService, + private readonly PackageDefinitionXmlParser _parser; + + /// + /// Constructor + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The file name for storing the package definitions (i.e. "createdPackages.config") + /// + /// + /// + /// + public PackagesRepository(IContentService contentService, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, IMacroService macroService, ILocalizationService languageService, IEntityXmlSerializer serializer, ILogger logger, + string packageRepositoryFileName, string tempFolderPath = null, string packagesFolderPath = null, string mediaFolderPath = null) { + if (string.IsNullOrWhiteSpace(packageRepositoryFileName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(packageRepositoryFileName)); _contentService = contentService; _contentTypeService = contentTypeService; _dataTypeService = dataTypeService; @@ -43,32 +67,38 @@ namespace Umbraco.Core.Packaging _languageService = languageService; _serializer = serializer; _logger = logger; - + _packageRepositoryFileName = packageRepositoryFileName; + _tempFolderPath = tempFolderPath ?? SystemDirectories.Data + "/TEMP/PackageFiles"; _packagesFolderPath = packagesFolderPath ?? SystemDirectories.Packages; _mediaFolderPath = mediaFolderPath ?? SystemDirectories.Media + "/created-packages"; + + _parser = new PackageDefinitionXmlParser(logger); } - private string CreatedPackagesFile => _packagesFolderPath.EnsureEndsWith('/') + "createdPackages.config"; + private string CreatedPackagesFile => _packagesFolderPath.EnsureEndsWith('/') + _packageRepositoryFileName; public IEnumerable GetAll() { var packagesXml = EnsureStorage(out _); + if (packagesXml?.Root == null) + yield break;; + foreach (var packageXml in packagesXml.Root.Elements("package")) - yield return XmlToPackageDefinition(packageXml); + yield return _parser.ToPackageDefinition(packageXml); } public PackageDefinition GetById(int id) { var packagesXml = EnsureStorage(out _); - var packageXml = packagesXml.Root.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); - return packageXml == null ? null : XmlToPackageDefinition(packageXml); + var packageXml = packagesXml?.Root?.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); + return packageXml == null ? null : _parser.ToPackageDefinition(packageXml); } public void Delete(int id) { var packagesXml = EnsureStorage(out var packagesFile); - var packageXml = packagesXml.Root.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); + var packageXml = packagesXml?.Root?.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); if (packageXml == null) return; packageXml.Remove(); @@ -82,6 +112,9 @@ namespace Umbraco.Core.Packaging var packagesXml = EnsureStorage(out var packagesFile); + if (packagesXml?.Root == null) + return false; + //ensure it's valid ValidatePackage(definition); @@ -97,9 +130,9 @@ namespace Umbraco.Core.Packaging var maxId = packagesXml.Root.Elements("package").Max(x => x.AttributeValue("id")) ?? 0; var newId = maxId + 1; definition.Id = newId; - definition.PackageId = Guid.NewGuid(); + definition.PackageId = definition.PackageId == default ? Guid.NewGuid() : definition.PackageId; definition.FolderId = Guid.NewGuid(); - var packageXml = PackageDefinitionToXml(definition); + var packageXml = _parser.ToXml(definition); packagesXml.Root.Add(packageXml); } else @@ -109,7 +142,7 @@ namespace Umbraco.Core.Packaging if (packageXml == null) return false; - var updatedXml = PackageDefinitionToXml(definition); + var updatedXml = _parser.ToXml(definition); packageXml.ReplaceWith(updatedXml); } @@ -154,10 +187,10 @@ namespace Umbraco.Core.Packaging AppendFileToManifest(fileName, temporaryPath, filesXml); //Load control on install... - if (!string.IsNullOrEmpty(definition.LoadControl)) + if (!string.IsNullOrEmpty(definition.Control)) { - var control = new XElement("control", definition.LoadControl); - AppendFileToManifest(definition.LoadControl, temporaryPath, filesXml); + var control = new XElement("control", definition.Control); + AppendFileToManifest(definition.Control, temporaryPath, filesXml); manifestRoot.Add(control); } @@ -174,7 +207,7 @@ namespace Umbraco.Core.Packaging } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); + _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); } } @@ -583,93 +616,9 @@ namespace Umbraco.Core.Packaging return packagesXml; } - private static PackageDefinition XmlToPackageDefinition(XElement xml) - { - if (xml == null) return null; + - var retVal = new PackageDefinition - { - Id = xml.AttributeValue("id"), - Name = xml.AttributeValue("name") ?? string.Empty, - FolderId = xml.AttributeValue("folder"), - PackagePath = xml.AttributeValue("packagePath") ?? string.Empty, - Version = xml.AttributeValue("version") ?? string.Empty, - Url = xml.AttributeValue("url") ?? string.Empty, - PackageId = xml.AttributeValue("packageGuid"), - IconUrl = xml.AttributeValue("iconUrl") ?? string.Empty, - UmbracoVersion = xml.AttributeValue("umbVersion"), - License = xml.Element("license")?.Value ?? string.Empty, - LicenseUrl = xml.Element("license")?.AttributeValue("url") ?? string.Empty, - Author = xml.Element("author")?.Value ?? string.Empty, - AuthorUrl = xml.Element("author")?.AttributeValue("url") ?? string.Empty, - Readme = xml.Element("readme")?.Value ?? string.Empty, - Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value - ContentNodeId = xml.Element("content")?.AttributeValue("nodeId") ?? string.Empty, - ContentLoadChildNodes = xml.Element("content")?.AttributeValue("loadChildNodes") ?? false, - Macros = xml.Element("macros")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - Templates = xml.Element("templates")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - Stylesheets = xml.Element("stylesheets")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - DocumentTypes = xml.Element("documentTypes")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - Languages = xml.Element("languages")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - DataTypes = xml.Element("datatypes")?.Value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - Files = xml.Element("files")?.Elements("file").Select(x => x.Value).ToList() ?? new List(), - LoadControl = xml.Element("loadcontrol")?.Value ?? string.Empty - }; - - return retVal; - } - - private XElement PackageDefinitionToXml(PackageDefinition def) - { - var actionsXml = new XElement("actions"); - try - { - actionsXml = XElement.Parse(def.Actions); - } - catch (Exception e) - { - _logger.Warn(e, "Could not add package actions to the package xml definition, the xml did not parse"); - } - - var packageXml = new XElement("package", - new XAttribute("id", def.Id), - new XAttribute("version", def.Version ?? string.Empty), - new XAttribute("url", def.Url ?? string.Empty), - new XAttribute("name", def.Name ?? string.Empty), - new XAttribute("folder", def.FolderId), - new XAttribute("packagePath", def.PackagePath ?? string.Empty), - new XAttribute("iconUrl", def.IconUrl ?? string.Empty), - new XAttribute("umbVersion", def.UmbracoVersion), - new XAttribute("packageGuid", def.PackageId), - - new XElement("license", - new XCData(def.License ?? string.Empty), - new XAttribute("url", def.LicenseUrl ?? string.Empty)), - - new XElement("author", - new XCData(def.Author ?? string.Empty), - new XAttribute("url", def.AuthorUrl ?? string.Empty)), - - new XElement("readme", new XCData(def.Readme ?? string.Empty)), - actionsXml, - new XElement("datatypes", string.Join(",", def.DataTypes ?? Array.Empty())), - - new XElement("content", - new XAttribute("nodeId", def.ContentNodeId), - new XAttribute("loadChildNodes", def.ContentLoadChildNodes)), - - new XElement("templates", string.Join(",", def.Templates ?? Array.Empty())), - new XElement("stylesheets", string.Join(",", def.Stylesheets ?? Array.Empty())), - new XElement("documentTypes", string.Join(",", def.DocumentTypes ?? Array.Empty())), - new XElement("macros", string.Join(",", def.Macros ?? Array.Empty())), - new XElement("files", (def.Files ?? Array.Empty()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))), - new XElement("languages", string.Join(",", def.Languages ?? Array.Empty())), - new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty())), - new XElement("loadcontrol", def.LoadControl ?? string.Empty)); //fixme: no more loadcontrol, needs to be an angular view - - return packageXml; - } + } } diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 32d5cd4c59..5b432d3339 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using System.Xml.Linq; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; @@ -9,11 +10,25 @@ namespace Umbraco.Core.Services { public interface IPackagingService : IService { + #region Installed Packages + + IEnumerable GetAllInstalledPackages(); + PackageDefinition GetInstalledPackageById(int id); + void DeleteInstalledPackage(int packageId, int userId = 0); + + /// + /// Persists a package definition to storage + /// + /// + bool SaveInstalledPackage(PackageDefinition definition); + + #endregion + #region Created Packages IEnumerable GetAllCreatedPackages(); PackageDefinition GetCreatedPackageById(int id); - void DeleteCreatedPackage(int id); + void DeleteCreatedPackage(int id, int userId = 0); /// /// Persists a package definition to storage @@ -111,6 +126,6 @@ namespace Umbraco.Core.Services /// /// The current user id performing the operation /// - string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId); + Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId); } } diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index d6003dc842..e7b33dd86d 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Text.RegularExpressions; +using System.Threading.Tasks; using System.Web; using System.Xml.Linq; using Umbraco.Core.Collections; @@ -41,12 +42,11 @@ namespace Umbraco.Core.Services.Implement private readonly IFileService _fileService; private readonly ILocalizationService _localizationService; private readonly IEntityService _entityService; - private readonly IScopeProvider _scopeProvider; private Dictionary _importedContentTypes; - private readonly IAuditRepository _auditRepository; - private readonly IContentTypeRepository _contentTypeRepository; + private readonly IAuditService _auditService; private readonly PropertyEditorCollection _propertyEditors; private readonly ICreatedPackagesRepository _createdPackages; + private readonly IInstalledPackagesRepository _installedPackages; private static HttpClient _httpClient; public PackagingService( @@ -58,11 +58,10 @@ namespace Umbraco.Core.Services.Implement IFileService fileService, ILocalizationService localizationService, IEntityService entityService, - IScopeProvider scopeProvider, - IAuditRepository auditRepository, - IContentTypeRepository contentTypeRepository, + IAuditService auditService, PropertyEditorCollection propertyEditors, - ICreatedPackagesRepository createdPackages) + ICreatedPackagesRepository createdPackages, + IInstalledPackagesRepository installedPackages) { _logger = logger; _contentService = contentService; @@ -72,21 +71,15 @@ namespace Umbraco.Core.Services.Implement _fileService = fileService; _localizationService = localizationService; _entityService = entityService; - _scopeProvider = scopeProvider; - _auditRepository = auditRepository; - _contentTypeRepository = contentTypeRepository; + _auditService = auditService; _propertyEditors = propertyEditors; _createdPackages = createdPackages; + _installedPackages = installedPackages; _importedContentTypes = new Dictionary(); } - protected IQuery Query() => _scopeProvider.SqlContext.Query(); - #region Content - - - /// /// Imports and saves package xml as @@ -229,43 +222,17 @@ namespace Umbraco.Core.Services.Implement content.Key = key; } - using (var scope = _scopeProvider.CreateScope(autoComplete: true)) + foreach (var property in properties) { - foreach (var property in properties) + string propertyTypeAlias = property.Name.LocalName; + if (content.HasProperty(propertyTypeAlias)) { - string propertyTypeAlias = property.Name.LocalName; - if (content.HasProperty(propertyTypeAlias)) - { - var propertyValue = property.Value; + var propertyValue = property.Value; - var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias); + var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias); - //TODO: It would be heaps nicer if we didn't have to hard code references to specific property editors - // we'd have to modify the packaging format to denote how to parse/store the value instead of relying on this - - if (propertyType != null) - { - // fixme - wtf is this very specific thing here?! - //if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.CheckBoxList) - //{ - - // //TODO: We need to refactor this so the packager isn't making direct db calls for an 'edge' case - // var database = scope.Database; - // var dtos = database.Fetch("WHERE datatypeNodeId = @Id", new { Id = propertyType.DataTypeId }); - - // var propertyValueList = new List(); - // foreach (var preValue in propertyValue.Split(',')) - // { - // propertyValueList.Add(dtos.Single(x => x.Value == preValue).Id.ToString(CultureInfo.InvariantCulture)); - // } - - // propertyValue = string.Join(",", propertyValueList.ToArray()); - - //} - } - //set property value - content.SetValue(propertyTypeAlias, propertyValue); - } + //set property value + content.SetValue(propertyTypeAlias, propertyValue); } } @@ -734,17 +701,12 @@ namespace Umbraco.Core.Services.Implement /// private IContentType FindContentTypeByAlias(string contentTypeAlias) { - using (var scope = _scopeProvider.CreateScope()) - { - var query = Query().Where(x => x.Alias == contentTypeAlias); - var contentType = _contentTypeRepository.Get(query).FirstOrDefault(); + var contentType = _contentTypeService.Get(contentTypeAlias); - if (contentType == null) - throw new Exception($"ContentType matching the passed in Alias: '{contentTypeAlias}' was null"); + if (contentType == null) + throw new Exception($"ContentType matching the passed in Alias: '{contentTypeAlias}' was null"); - scope.Complete(); - return contentType; - } + return contentType; } #endregion @@ -1165,59 +1127,45 @@ namespace Umbraco.Core.Services.Implement #region Package Files - /// - /// This will fetch an Umbraco package file from the package repository and return the relative file path to the downloaded package file - /// - /// - /// - /// /// The current user id performing the operation - /// - public string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId) + /// + public async Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId) { - using (var scope = _scopeProvider.CreateScope()) + //includeHidden = true because we don't care if it's hidden we want to get the file regardless + var url = $"{Constants.PackageRepository.RestApiBaseUrl}/{packageId}?version={umbracoVersion.ToString(3)}&includeHidden=true&asFile=true"; + byte[] bytes; + try { - //includeHidden = true because we don't care if it's hidden we want to get the file regardless - var url = $"{Constants.PackageRepository.RestApiBaseUrl}/{packageId}?version={umbracoVersion.ToString(3)}&includeHidden=true&asFile=true"; - byte[] bytes; - try + if (_httpClient == null) { - if (_httpClient == null) - { - _httpClient = new HttpClient(); - } - bytes = _httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult(); + _httpClient = new HttpClient(); } - catch (HttpRequestException ex) - { - throw new ConnectionException("An error occuring downloading the package from " + url, ex); - } - - //successfull - if (bytes.Length > 0) - { - var packagePath = IOHelper.MapPath(SystemDirectories.Packages); - - // Check for package directory - if (Directory.Exists(packagePath) == false) - Directory.CreateDirectory(packagePath); - - var packageFilePath = Path.Combine(packagePath, packageId + ".umb"); - - using (var fs1 = new FileStream(packageFilePath, FileMode.Create)) - { - fs1.Write(bytes, 0, bytes.Length); - return "packages\\" + packageId + ".umb"; - } - } - - Audit(AuditType.PackagerInstall, $"Package {packageId} fetched from {Constants.PackageRepository.DefaultRepositoryId}", userId, -1); - return null; + bytes = await _httpClient.GetByteArrayAsync(url); + } + catch (HttpRequestException ex) + { + throw new ConnectionException("An error occuring downloading the package from " + url, ex); } - } - private void Audit(AuditType type, string message, int userId, int objectId) - { - _auditRepository.Save(new AuditItem(objectId, type, userId, "Package", message)); + //successfull + if (bytes.Length > 0) + { + var packagePath = IOHelper.MapPath(SystemDirectories.Packages); + + // Check for package directory + if (Directory.Exists(packagePath) == false) + Directory.CreateDirectory(packagePath); + + var packageFilePath = Path.Combine(packagePath, packageId + ".umb"); + + using (var fs1 = new FileStream(packageFilePath, FileMode.Create)) + { + fs1.Write(bytes, 0, bytes.Length); + return "packages\\" + packageId + ".umb"; + } + } + + _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package {packageId} fetched from {Constants.PackageRepository.DefaultRepositoryId}"); + return null; } #endregion @@ -1369,21 +1317,13 @@ namespace Umbraco.Core.Services.Implement { var metaData = GetPackageMetaData(packageFilePath); - if (raiseEvents) - { - if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFilePath, metaData), this)) - { - var initEmpty = new InstallationSummary().InitEmpty(); - initEmpty.MetaData = metaData; - return initEmpty; - } - } + if (raiseEvents && ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFilePath, metaData), this)) + return new InstallationSummary { MetaData = metaData }; + var installationSummary = PackageInstallation.InstallPackage(packageFilePath, userId); if (raiseEvents) - { ImportedPackage.RaiseEvent(new ImportPackageEventArgs(installationSummary, metaData, false), this); - } return installationSummary; } @@ -1393,16 +1333,23 @@ namespace Umbraco.Core.Services.Implement return PackageInstallation.GetPreInstallWarnings(packageFilePath); } - internal MetaData GetPackageMetaData(string packageFilePath) + internal IPackageInfo GetPackageMetaData(string packageFilePath) { return PackageInstallation.GetMetaData(packageFilePath); } #endregion - #region Package Building + #region Created/Installed Package Repositories - public void DeleteCreatedPackage(int id) => _createdPackages.Delete(id); + public void DeleteCreatedPackage(int id, int userId = 0) + { + var package = GetCreatedPackageById(id); + if (package == null) return; + + _auditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", $"Created package '{package.Name}' deleted. Package id: {package.Id}"); + _createdPackages.Delete(id); + } public IEnumerable GetAllCreatedPackages() => _createdPackages.GetAll(); @@ -1412,6 +1359,22 @@ namespace Umbraco.Core.Services.Implement public string ExportCreatedPackage(PackageDefinition definition) => _createdPackages.ExportPackage(definition); + + public IEnumerable GetAllInstalledPackages() => _installedPackages.GetAll(); + + public PackageDefinition GetInstalledPackageById(int id) => _installedPackages.GetById(id); + + public bool SaveInstalledPackage(PackageDefinition definition) => _installedPackages.SavePackage(definition); + + public void DeleteInstalledPackage(int packageId, int userId = 0) + { + var package = GetInstalledPackageById(packageId); + if (package == null) return; + + _auditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", $"Installed package '{package.Name}' deleted. Package id: {package.Id}"); + _installedPackages.Delete(packageId); + } + #endregion /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index bad9ba7ccd..038d531bd4 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -430,7 +430,8 @@ - + + @@ -443,13 +444,13 @@ - - - + + + @@ -769,7 +770,6 @@ - @@ -893,7 +893,6 @@ - @@ -1535,7 +1534,6 @@ - \ No newline at end of file diff --git a/src/Umbraco.Core/Xml/XmlHelper.cs b/src/Umbraco.Core/Xml/XmlHelper.cs index d4f2d40656..e058858799 100644 --- a/src/Umbraco.Core/Xml/XmlHelper.cs +++ b/src/Umbraco.Core/Xml/XmlHelper.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Xml /// /// The XmlHelper class contains general helper methods for working with xml in umbraco. /// - public class XmlHelper + internal class XmlHelper { /// /// Creates or sets an attribute on the XmlNode if an Attributes collection is available @@ -126,44 +126,6 @@ namespace Umbraco.Core.Xml return false; } - /// - /// Tries to create a new XElement from a property value. - /// - /// The value of the property. - /// The Xml element. - /// A value indicating whether it has been possible to create the element. - /// The value can be anything... Performance-wise, this is bad. - public static bool TryCreateXElementFromPropertyValue(object value, out XElement elt) - { - // see note above in TryCreateXPathDocumentFromPropertyValue... - - elt = null; - var xml = value as string; - if (xml == null) return false; // not a string - if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml - if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise - - try - { - elt = XElement.Parse(xml, LoadOptions.None); - } - catch - { - elt = null; - return false; // string can't be parsed into xml - } - - //SD: This used to do this but the razor macros and the entire razor macros section is gone, it was all legacy, it seems this method isn't even - // used apart from for tests so don't think this matters. In any case, we no longer check for this! - - //var name = elt.Name.LocalName; // must not match an excluded tag - //if (UmbracoConfig.For.UmbracoSettings().Scripting.NotDynamicXmlDocumentElements.All(x => x.Element.InvariantEquals(name) == false)) - // return true; - //elt = null; - //return false; - - return true; - } /// /// Sorts the children of a parentNode. @@ -186,47 +148,6 @@ namespace Umbraco.Core.Xml parentNode.AppendChild(node); // moves the node to the last position } - /// - /// Sorts the children of a parentNode if needed. - /// - /// The parent node. - /// An XPath expression to select children of to sort. - /// A function returning the value to order the nodes by. - /// A value indicating whether sorting was needed. - /// same as SortNodes but will do nothing if nodes are already sorted - should improve performances. - internal static bool SortNodesIfNeeded( - XmlNode parentNode, - string childNodesXPath, - Func orderBy) - { - // ensure orderBy runs only once per node - // checks whether nodes are already ordered - // and actually sorts only if needed - - var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast() - .Select(x => Tuple.Create(x, orderBy(x))).ToArray(); - - var a = 0; - foreach (var x in childNodesAndOrder) - { - if (a > x.Item2) - { - a = -1; - break; - } - a = x.Item2; - } - - if (a >= 0) - return false; - - // append child nodes to last position, in sort-order - // so all child nodes will go after the property nodes - foreach (var x in childNodesAndOrder.OrderBy(x => x.Item2)) - parentNode.AppendChild(x.Item1); // moves the node to the last position - - return true; - } /// /// Sorts a single child node of a parentNode. @@ -281,72 +202,6 @@ namespace Umbraco.Core.Xml return false; } - // used by DynamicNode only, see note in TryCreateXPathDocumentFromPropertyValue - public static string StripDashesInElementOrAttributeNames(string xml) - { - using (var outputms = new MemoryStream()) - { - using (TextWriter outputtw = new StreamWriter(outputms)) - { - using (var ms = new MemoryStream()) - { - using (var tw = new StreamWriter(ms)) - { - tw.Write(xml); - tw.Flush(); - ms.Position = 0; - using (var tr = new StreamReader(ms)) - { - bool IsInsideElement = false, IsInsideQuotes = false; - int ic = 0; - while ((ic = tr.Read()) != -1) - { - if (ic == (int)'<' && !IsInsideQuotes) - { - if (tr.Peek() != (int)'!') - { - IsInsideElement = true; - } - } - if (ic == (int)'>' && !IsInsideQuotes) - { - IsInsideElement = false; - } - if (ic == (int)'"') - { - IsInsideQuotes = !IsInsideQuotes; - } - if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes) - { - outputtw.Write((char)ic); - } - } - - } - } - } - outputtw.Flush(); - outputms.Position = 0; - using (TextReader outputtr = new StreamReader(outputms)) - { - return outputtr.ReadToEnd(); - } - } - } - } - - - /// - /// Imports a XML node from text. - /// - /// The text. - /// The XML doc. - /// - public static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc) - { - xmlDoc.LoadXml(text); - return xmlDoc.FirstChild; - } /// /// Opens a file as a XmlDocument. @@ -355,16 +210,14 @@ namespace Umbraco.Core.Xml /// Returns a XmlDocument class public static XmlDocument OpenAsXmlDocument(string filePath) { - - var reader = new XmlTextReader(IOHelper.MapPath(filePath)) {WhitespaceHandling = WhitespaceHandling.All}; - - var xmlDoc = new XmlDocument(); - //Load the file into the XmlDocument - xmlDoc.Load(reader); - //Close off the connection to the file. - reader.Close(); - - return xmlDoc; + using (var reader = new XmlTextReader(IOHelper.MapPath(filePath)) {WhitespaceHandling = WhitespaceHandling.All}) + { + var xmlDoc = new XmlDocument(); + //Load the file into the XmlDocument + xmlDoc.Load(reader); + + return xmlDoc; + } } /// diff --git a/src/Umbraco.Core/_Legacy/PackageActions/IPackageAction.cs b/src/Umbraco.Core/_Legacy/PackageActions/IPackageAction.cs index 502aee36b3..b58ea34a60 100644 --- a/src/Umbraco.Core/_Legacy/PackageActions/IPackageAction.cs +++ b/src/Umbraco.Core/_Legacy/PackageActions/IPackageAction.cs @@ -1,13 +1,13 @@ using System.Xml; +using System.Xml.Linq; using Umbraco.Core.Composing; namespace Umbraco.Core._Legacy.PackageActions { public interface IPackageAction : IDiscoverable { - bool Execute(string packageName, XmlNode xmlData); + bool Execute(string packageName, XElement xmlData); string Alias(); - bool Undo(string packageName, XmlNode xmlData); - XmlNode SampleXml(); + bool Undo(string packageName, XElement xmlData); } } diff --git a/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs b/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs index d100713102..75030decbf 100644 --- a/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs +++ b/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Xml; +using System.Xml.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -41,7 +42,7 @@ namespace Umbraco.Tests.Composing public class PackageAction1 : IPackageAction { - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { throw new NotImplementedException(); } @@ -51,7 +52,7 @@ namespace Umbraco.Tests.Composing return "pa1"; } - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { throw new NotImplementedException(); } @@ -64,7 +65,7 @@ namespace Umbraco.Tests.Composing public class PackageAction2 : IPackageAction { - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { throw new NotImplementedException(); } @@ -74,7 +75,7 @@ namespace Umbraco.Tests.Composing return "pa2"; } - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs index 3bd9b50ed4..40500d6bcb 100644 --- a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs @@ -37,10 +37,11 @@ namespace Umbraco.Tests.Packaging Directory.Delete(IOHelper.MapPath("~/" + _testBaseFolder), true); } - public ICreatedPackagesRepository PackageBuilder => new CreatedPackagesRepository( + public ICreatedPackagesRepository PackageBuilder => new PackagesRepository( ServiceContext.ContentService, ServiceContext.ContentTypeService, ServiceContext.DataTypeService, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, Factory.GetInstance(), Logger, + "createdPackages.config", //temp paths tempFolderPath: "~/" + _testBaseFolder + "/temp", packagesFolderPath: "~/" + _testBaseFolder + "/packages", diff --git a/src/Umbraco.Tests/Services/PackagingServiceTests.cs b/src/Umbraco.Tests/Services/PackagingServiceTests.cs index 2caf3e08b3..0f57298c88 100644 --- a/src/Umbraco.Tests/Services/PackagingServiceTests.cs +++ b/src/Umbraco.Tests/Services/PackagingServiceTests.cs @@ -46,7 +46,7 @@ namespace Umbraco.Tests.Services string testPackagePath = GetTestPackagePath(documentTypePickerUmb); - MetaData packageMetaData = packagingService.GetPackageMetaData(testPackagePath); + var packageMetaData = packagingService.GetPackageMetaData(testPackagePath); Assert.IsNotNull(packageMetaData); } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 105bc440cc..f48b72daf9 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -169,9 +169,11 @@ namespace Umbraco.Tests.TestHelpers var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); var packagingService = GetLazyService(factory, c => new PackagingService( - logger, contentService.Value, contentTypeService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, scopeProvider, GetRepo(c), GetRepo(c), new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())), - new CreatedPackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, - new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger))); + logger, contentService.Value, contentTypeService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, auditService.Value, new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())), + createdPackages: new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "createdPackages.config"), + installedPackages: new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "installedPackages.config"))); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 86f3e48b7c..4b452ac6a6 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -72,7 +72,7 @@ namespace Umbraco.Web.Editors [HttpDelete] public IHttpActionResult DeleteCreatedPackage(int packageId) { - Services.PackagingService.DeleteCreatedPackage(packageId); + Services.PackagingService.DeleteCreatedPackage(packageId, Security.GetUserId().ResultOr(0)); return Ok(); } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 55e843aceb..73d50eb48a 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -8,6 +8,7 @@ using System.Net.Http; using System.Threading.Tasks; using System.Web.Http; using System.Xml; +using System.Xml.Linq; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; @@ -29,7 +30,6 @@ using Umbraco.Web.UI.JavaScript; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; using Umbraco.Web._Legacy.Packager; -using Umbraco.Web._Legacy.Packager.PackageInstance; using File = System.IO.File; using Notification = Umbraco.Web.Models.ContentEditing.Notification; using Version = System.Version; @@ -73,17 +73,17 @@ namespace Umbraco.Web.Editors { try { - var pack = InstalledPackage.GetById(packageId); - if (pack == null) return NotFound(); + var package = Services.PackagingService.GetInstalledPackageById(packageId); + if (package == null) return NotFound(); - PerformUninstall(pack); + PerformUninstall(package); //now get all other packages by this name since we'll uninstall all versions - foreach (var installed in InstalledPackage.GetAllInstalledPackages() - .Where(x => x.Data.Name == pack.Data.Name && x.Data.Id != pack.Data.Id)) + foreach (var installed in Services.PackagingService.GetAllInstalledPackages() + .Where(x => x.Name == package.Name && x.Id != package.Id)) { - //remove from teh xml - installed.Delete(Security.GetUserId().ResultOr(0)); + //remove from the xml + Services.PackagingService.DeleteInstalledPackage(installed.Id, Security.GetUserId().ResultOr(0)); } } catch (Exception ex) @@ -98,10 +98,10 @@ namespace Umbraco.Web.Editors /// /// SORRY :( I didn't have time to put this in a service somewhere - the old packager did this all manually too /// - /// - protected void PerformUninstall(InstalledPackage pack) + /// + protected void PerformUninstall(PackageDefinition package) { - if (pack == null) throw new ArgumentNullException("pack"); + if (package == null) throw new ArgumentNullException("package"); var removedTemplates = new List(); var removedMacros = new List(); @@ -111,7 +111,7 @@ namespace Umbraco.Web.Editors var removedFiles = new List(); //Uninstall templates - foreach (var item in pack.Data.Templates.ToArray()) + foreach (var item in package.Templates.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) continue; @@ -121,11 +121,11 @@ namespace Umbraco.Web.Editors removedTemplates.Add(found); Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId().ResultOr(0)); } - pack.Data.Templates.Remove(nId.ToString()); + package.Templates.Remove(nId.ToString()); } //Uninstall macros - foreach (var item in pack.Data.Macros.ToArray()) + foreach (var item in package.Macros.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) continue; @@ -135,20 +135,20 @@ namespace Umbraco.Web.Editors removedMacros.Add(macro); Services.MacroService.Delete(macro); } - pack.Data.Macros.Remove(nId.ToString()); + package.Macros.Remove(nId.ToString()); } //Remove Document Types var contentTypes = new List(); var contentTypeService = Services.ContentTypeService; - foreach (var item in pack.Data.DocumentTypes.ToArray()) + foreach (var item in package.DocumentTypes.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) continue; var contentType = contentTypeService.Get(nId); if (contentType == null) continue; contentTypes.Add(contentType); - pack.Data.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); + package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); } //Order the DocumentTypes before removing them @@ -163,7 +163,7 @@ namespace Umbraco.Web.Editors } //Remove Dictionary items - foreach (var item in pack.Data.DictionaryItems.ToArray()) + foreach (var item in package.DictionaryItems.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) continue; @@ -173,11 +173,11 @@ namespace Umbraco.Web.Editors removedDictionaryItems.Add(di); Services.LocalizationService.Delete(di); } - pack.Data.DictionaryItems.Remove(nId.ToString()); + package.DictionaryItems.Remove(nId.ToString()); } //Remove Data types - foreach (var item in pack.Data.DataTypes.ToArray()) + foreach (var item in package.DataTypes.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) continue; @@ -187,28 +187,27 @@ namespace Umbraco.Web.Editors removedDataTypes.Add(dtd); Services.DataTypeService.Delete(dtd); } - pack.Data.DataTypes.Remove(nId.ToString()); + package.DataTypes.Remove(nId.ToString()); } - pack.Save(); + Services.PackagingService.SaveInstalledPackage(package); // uninstall actions //TODO: We should probably report errors to the UI!! // This never happened before though, but we should do something now - if (pack.Data.Actions.IsNullOrWhiteSpace() == false) + if (package.Actions.IsNullOrWhiteSpace() == false) { try { - var actionsXml = new XmlDocument(); - actionsXml.LoadXml("" + pack.Data.Actions + ""); + var actionsXml = XDocument.Parse("" + package.Actions + ""); - Logger.Debug("Executing undo actions: {UndoActionsXml}", actionsXml.OuterXml); + Logger.Debug("Executing undo actions: {UndoActionsXml}", actionsXml.ToString(SaveOptions.DisableFormatting)); - foreach (XmlNode n in actionsXml.DocumentElement.SelectNodes("//Action")) + foreach (var n in actionsXml.Root.Elements("Action")) { try { - _packageActionRunner.UndoPackageAction(pack.Data.Name, n.Attributes["alias"].Value, n); + _packageActionRunner.UndoPackageAction(package.Name, n.AttributeValue("alias"), n); } catch (Exception ex) { @@ -224,7 +223,7 @@ namespace Umbraco.Web.Editors //moved remove of files here so custom package actions can still undo //Remove files - foreach (var item in pack.Data.Files.ToArray()) + foreach (var item in package.Files.ToArray()) { removedFiles.Add(item.GetRelativePath()); @@ -240,15 +239,17 @@ namespace Umbraco.Web.Editors File.Delete(filePath); } - pack.Data.Files.Remove(file); + package.Files.Remove(file); } - pack.Save(); - pack.Delete(Security.GetUserId().ResultOr(0)); + + Services.PackagingService.SaveInstalledPackage(package); + + Services.PackagingService.DeleteInstalledPackage(package.Id, Security.GetUserId().ResultOr(0)); // create a summary of what was actually removed, for PackagingService.UninstalledPackage var summary = new UninstallationSummary { - MetaData = pack.GetMetaData(), + MetaData = package, TemplatesUninstalled = removedTemplates, MacrosUninstalled = removedMacros, ContentTypesUninstalled = removedContentTypes, @@ -259,7 +260,7 @@ namespace Umbraco.Web.Editors }; // trigger the UninstalledPackage event - PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs(summary, false)); + PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs(summary, package, false)); } @@ -269,18 +270,14 @@ namespace Umbraco.Web.Editors /// public IEnumerable GetInstalled() { - return InstalledPackage.GetAllInstalledPackages() + return Services.PackagingService.GetAllInstalledPackages() .GroupBy( //group by name - x => x.Data.Name, + x => x.Name, //select the package with a parsed version - pck => - { - Version pckVersion; - return Version.TryParse(pck.Data.Version, out pckVersion) - ? new { package = pck, version = pckVersion } - : new { package = pck, version = new Version(0, 0, 0) }; - }) + pck => Version.TryParse(pck.Version, out var pckVersion) + ? new { package = pck, version = pckVersion } + : new { package = pck, version = new Version(0, 0, 0) }) .Select(grouping => { //get the max version for the package @@ -290,15 +287,15 @@ namespace Umbraco.Web.Editors }) .Select(pack => new InstalledPackageModel { - Name = pack.Data.Name, - Id = pack.Data.Id, - Author = pack.Data.Author, - Version = pack.Data.Version, - Url = pack.Data.Url, - License = pack.Data.License, - LicenseUrl = pack.Data.LicenseUrl, - Files = pack.Data.Files, - IconUrl = pack.Data.IconUrl + Name = pack.Name, + Id = pack.Id, + Author = pack.Author, + Version = pack.Version, + Url = pack.Url, + License = pack.License, + LicenseUrl = pack.LicenseUrl, + Files = pack.Files, + IconUrl = pack.IconUrl }) .ToList(); } @@ -320,7 +317,6 @@ namespace Umbraco.Web.Editors model.ConflictingMacroAliases = ins.ConflictingMacroAliases; model.ConflictingStyleSheetNames = ins.ConflictingStyleSheetNames; model.ConflictingTemplateAliases = ins.ConflictingTemplateAliases; - model.ContainsBinaryFileErrors = ins.ContainsBinaryFileErrors; model.ContainsMacroConflict = ins.ContainsMacroConflict; model.ContainsStyleSheetConflicts = ins.ContainsStyleSheeConflicts; model.ContainsTemplateConflicts = ins.ContainsTemplateConflicts; @@ -346,19 +342,17 @@ namespace Umbraco.Web.Editors private bool ValidateInstalledInternal(string name, string version) { - var allInstalled = InstalledPackage.GetAllInstalledPackages(); + var allInstalled = Services.PackagingService.GetAllInstalledPackages(); var found = allInstalled.FirstOrDefault(x => { - if (x.Data.Name != name) return false; + if (x.Name != name) return false; //match the exact version - if (x.Data.Version == version) + if (x.Version == version) { return true; } //now try to compare the versions - Version installed; - Version selected; - if (Version.TryParse(x.Data.Version, out installed) && Version.TryParse(version, out selected)) + if (Version.TryParse(x.Version, out var installed) && Version.TryParse(version, out var selected)) { if (installed >= selected) return true; } @@ -456,13 +450,13 @@ namespace Umbraco.Web.Editors /// /// [HttpGet] - public LocalPackageInstallModel Fetch(string packageGuid) + public async Task Fetch(string packageGuid) { //Default path string path = Path.Combine("packages", packageGuid + ".umb"); if (File.Exists(IOHelper.MapPath(Path.Combine(SystemDirectories.Data, path))) == false) { - path = Services.PackagingService.FetchPackageFile(Guid.Parse(packageGuid), UmbracoVersion.Current, Security.GetUserId().ResultOr(0)); + path = await Services.PackagingService.FetchPackageFileAsync(Guid.Parse(packageGuid), UmbracoVersion.Current, Security.GetUserId().ResultOr(0)); } var model = new LocalPackageInstallModel @@ -495,7 +489,7 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel Import(PackageInstallModel model) { - var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); + var ins = new Installer(Security.CurrentUser.Id); var tempPath = ins.Import(model.ZipFilePath); //now we need to check for version comparison @@ -510,7 +504,7 @@ namespace Umbraco.Web.Editors } model.TemporaryDirectoryPath = Path.Combine(SystemDirectories.Data, tempPath); - model.Id = ins.CreateManifest(IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid, model.RepositoryGuid.ToString()); + model.Id = ins.CreateManifest(model.PackageGuid); return model; } @@ -523,7 +517,7 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel InstallFiles(PackageInstallModel model) { - var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); + var ins = new Installer(Security.CurrentUser.Id); ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); ins.InstallFiles(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs index 55680084e5..ac859ee3aa 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Text; +using System.Threading.Tasks; using System.Web; using System.Web.Http; using Newtonsoft.Json.Linq; @@ -10,6 +11,7 @@ using umbraco; using Umbraco.Core; using Umbraco.Web.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; using Umbraco.Web.WebApi; @@ -28,8 +30,12 @@ namespace Umbraco.Web.Install.Controllers [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] public class InstallPackageController : ApiController { - public InstallPackageController() - { } + private readonly IPackagingService _packagingService; + + public InstallPackageController(IPackagingService packagingService) + { + _packagingService = packagingService; + } private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66"; @@ -49,18 +55,18 @@ namespace Umbraco.Web.Install.Controllers /// /// [HttpPost] - public HttpResponseMessage DownloadPackageFiles(InstallPackageModel model) + public async Task DownloadPackageFiles(InstallPackageModel model) { - var packageFile = Current.Services.PackagingService.FetchPackageFile( + var packageFile = await _packagingService.FetchPackageFileAsync( model.KitGuid, UmbracoVersion.Current, UmbracoContext.Current.Security.CurrentUser.Id); - var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); + var installer = new _Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); var tempFile = installer.Import(packageFile); installer.LoadConfig(tempFile); - var pId = installer.CreateManifest(tempFile, model.KitGuid, RepoGuid); + var pId = installer.CreateManifest(model.KitGuid); return Json(new { success = true, diff --git a/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs b/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs index de53fd60cf..f71d486f5a 100644 --- a/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs +++ b/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Threading.Tasks; using System.Web.Configuration; using System.Xml.Linq; using Umbraco.Core.IO; @@ -30,7 +31,7 @@ namespace Umbraco.Web.Install.InstallSteps /// /// /// - public override InstallSetupResult Execute(bool? model) + public override Task ExecuteAsync(bool? model) { if (model.HasValue && model.Value == false) return null; @@ -50,7 +51,7 @@ namespace Umbraco.Web.Install.InstallSteps xml.Save(fileName, SaveOptions.DisableFormatting); - return null; + return Task.FromResult(null); } public override bool RequiresExecution(bool? model) diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs index 2fe6c0ceda..9d1aec1c71 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs @@ -1,5 +1,6 @@ using System; using System.Configuration; +using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; @@ -20,7 +21,7 @@ namespace Umbraco.Web.Install.InstallSteps _databaseBuilder = databaseBuilder; } - public override InstallSetupResult Execute(DatabaseModel database) + public override Task ExecuteAsync(DatabaseModel database) { //if the database model is null then we will apply the defaults if (database == null) @@ -33,7 +34,7 @@ namespace Umbraco.Web.Install.InstallSteps throw new InstallException("Could not connect to the database"); } ConfigureConnection(database); - return null; + return Task.FromResult(null); } private void ConfigureConnection(DatabaseModel database) diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs index a9daee6e95..812889b977 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Configuration; +using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; @@ -24,7 +25,7 @@ namespace Umbraco.Web.Install.InstallSteps _logger = logger; } - public override InstallSetupResult Execute(object model) + public override Task ExecuteAsync(object model) { if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); @@ -43,10 +44,10 @@ namespace Umbraco.Web.Install.InstallSteps } //upgrade is required so set the flag for the next step - return new InstallSetupResult(new Dictionary + return Task.FromResult(new InstallSetupResult(new Dictionary { {"upgrade", true} - }); + })); } internal static void HandleConnectionStrings(ILogger logger) diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index 8283eb6bef..e8046bd196 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -1,6 +1,7 @@ using System; using System.Configuration; using System.Linq; +using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; @@ -23,7 +24,7 @@ namespace Umbraco.Web.Install.InstallSteps _logger = logger; } - public override InstallSetupResult Execute(object model) + public override Task ExecuteAsync(object model) { var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "DatabaseInstall"); @@ -43,7 +44,7 @@ namespace Umbraco.Web.Install.InstallSteps DatabaseInstallStep.HandleConnectionStrings(_logger); } - return null; + return Task.FromResult(null); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs b/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs index 6d07190b4f..c5bc9ac047 100644 --- a/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; using umbraco; using Umbraco.Core; using Umbraco.Core.IO; @@ -13,7 +14,7 @@ namespace Umbraco.Web.Install.InstallSteps PerformsAppRestart = true)] internal class FilePermissionsStep : InstallSetupStep { - public override InstallSetupResult Execute(object model) + public override Task ExecuteAsync(object model) { // validate file permissions Dictionary> report; @@ -22,7 +23,7 @@ namespace Umbraco.Web.Install.InstallSteps if (permissionsOk == false) throw new InstallException("Permission check failed", "permissionsreport", new { errors = report }); - return null; + return Task.FromResult(null); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs index 64b8568fe5..9132f5cd49 100644 --- a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs @@ -4,6 +4,7 @@ using System.Configuration; using System.Net; using System.Net.Http; using System.Text; +using System.Threading.Tasks; using System.Web; using System.Web.Security; using Newtonsoft.Json; @@ -51,7 +52,7 @@ namespace Umbraco.Web.Install.InstallSteps } } - public override InstallSetupResult Execute(UserModel user) + public override Task ExecuteAsync(UserModel user) { var admin = _userService.GetUserById(Constants.Security.SuperUserId); if (admin == null) @@ -99,7 +100,7 @@ namespace Umbraco.Web.Install.InstallSteps catch { /* fail in silence */ } } - return null; + return Task.FromResult(null); } /// diff --git a/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs b/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs index 0cac3fe91f..3e836397fd 100644 --- a/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs @@ -1,4 +1,5 @@ -using System.Web; +using System.Threading.Tasks; +using System.Web; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; @@ -31,7 +32,7 @@ namespace Umbraco.Web.Install.InstallSteps _distributedCache = distributedCache; } - public override InstallSetupResult Execute(object model) + public override Task ExecuteAsync(object model) { //During a new install we'll log the default user in (which is id = 0). // During an upgrade, the user will already need to be logged in in order to run the installer. @@ -56,7 +57,7 @@ namespace Umbraco.Web.Install.InstallSteps //reports the ended install _installHelper.InstallStatus(true, ""); - return null; + return Task.FromResult(null); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs index 9345a0fc96..075a61ca95 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using System.Web; using Umbraco.Web.Install.Models; using Umbraco.Web._Legacy.Packager; @@ -10,7 +11,7 @@ namespace Umbraco.Web.Install.InstallSteps "StarterKitCleanup", 32, "Almost done")] internal class StarterKitCleanupStep : InstallSetupStep { - public override InstallSetupResult Execute(object model) + public override Task ExecuteAsync(object model) { var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "StarterKitDownload"); @@ -19,7 +20,7 @@ namespace Umbraco.Web.Install.InstallSteps CleanupInstallation(manifestId, packageFile); - return null; + return Task.FromResult(null); } private void CleanupInstallation(int manifestId, string packageFile) diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index c79be96a93..66d1b0a20c 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using System.Web; using Umbraco.Core.Services; using Umbraco.Core.Configuration; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; -using Umbraco.Web.Security; using Umbraco.Web._Legacy.Packager; -using Umbraco.Web._Legacy.Packager.PackageInstance; namespace Umbraco.Web.Install.InstallSteps { @@ -20,17 +19,19 @@ namespace Umbraco.Web.Install.InstallSteps private readonly InstallHelper _installHelper; private readonly UmbracoContext _umbracoContext; private readonly IContentService _contentService; + private readonly IPackagingService _packageService; - public StarterKitDownloadStep(IContentService contentService, InstallHelper installHelper, UmbracoContext umbracoContext) + public StarterKitDownloadStep(IContentService contentService, IPackagingService packageService, InstallHelper installHelper, UmbracoContext umbracoContext) { _installHelper = installHelper; _umbracoContext = umbracoContext; _contentService = contentService; + _packageService = packageService; } private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66"; - public override InstallSetupResult Execute(Guid? starterKitId) + public override async Task ExecuteAsync(Guid? starterKitId) { //if there is no value assigned then use the default starter kit if (starterKitId.HasValue == false) @@ -48,7 +49,7 @@ namespace Umbraco.Web.Install.InstallSteps return null; } - var result = DownloadPackageFiles(starterKitId.Value); + var result = await DownloadPackageFilesAsync(starterKitId.Value); Current.RestartAppPool(); @@ -59,16 +60,16 @@ namespace Umbraco.Web.Install.InstallSteps }); } - private Tuple DownloadPackageFiles(Guid kitGuid) + private async Task> DownloadPackageFilesAsync(Guid kitGuid) { var installer = new Installer(); //Go get the package file from the package repo - var packageFile = Current.Services.PackagingService.FetchPackageFile(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); + var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); var tempFile = installer.Import(packageFile); installer.LoadConfig(tempFile); - var pId = installer.CreateManifest(tempFile, kitGuid, RepoGuid); + var pId = installer.CreateManifest(kitGuid); InstallPackageFiles(pId, tempFile); @@ -84,10 +85,7 @@ namespace Umbraco.Web.Install.InstallSteps } - public override string View - { - get { return (InstalledPackage.GetAllInstalledPackages().Count > 0) ? string.Empty : base.View; } - } + public override string View => _packageService.GetAllInstalledPackages().Any() ? string.Empty : base.View; public override bool RequiresExecution(Guid? model) { @@ -97,7 +95,7 @@ namespace Umbraco.Web.Install.InstallSteps return false; } - if (InstalledPackage.GetAllInstalledPackages().Count > 0) + if (_packageService.GetAllInstalledPackages().Any()) return false; if (_contentService.GetRootContent().Any()) diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 8bec4ca199..0e189c5a6d 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using System.Web; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; @@ -20,7 +21,7 @@ namespace Umbraco.Web.Install.InstallSteps } - public override InstallSetupResult Execute(object model) + public override Task ExecuteAsync(object model) { var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "StarterKitDownload"); @@ -31,7 +32,7 @@ namespace Umbraco.Web.Install.InstallSteps Current.RestartAppPool(_httContext); - return null; + return Task.FromResult(null); } private void InstallBusinessLogic(int manifestId, string packageFile) diff --git a/src/Umbraco.Web/Install/InstallSteps/UpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/UpgradeStep.cs index 7ed3de6471..5f44555092 100644 --- a/src/Umbraco.Web/Install/InstallSteps/UpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/UpgradeStep.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Web.Install.Models; @@ -13,7 +14,7 @@ namespace Umbraco.Web.Install.InstallSteps { public override bool RequiresExecution(object model) => true; - public override InstallSetupResult Execute(object model) => null; + public override Task ExecuteAsync(object model) => Task.FromResult(null); public override object ViewModel { diff --git a/src/Umbraco.Web/Install/Models/InstallSetupStep.cs b/src/Umbraco.Web/Install/Models/InstallSetupStep.cs index 36cf838a82..3b017368f9 100644 --- a/src/Umbraco.Web/Install/Models/InstallSetupStep.cs +++ b/src/Umbraco.Web/Install/Models/InstallSetupStep.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.Serialization; +using System.Threading.Tasks; using Umbraco.Core; namespace Umbraco.Web.Install.Models @@ -14,17 +15,14 @@ namespace Umbraco.Web.Install.Models /// Defines the step model type on the server side so we can bind it /// [IgnoreDataMember] - public override Type StepType - { - get { return typeof(T); } - } + public override Type StepType => typeof(T); /// /// The step execution method /// /// /// - public abstract InstallSetupResult Execute(T model); + public abstract Task ExecuteAsync(T model); /// /// Determines if this step needs to execute based on the current state of the application and/or install process @@ -86,10 +84,6 @@ namespace Umbraco.Web.Install.Models public abstract Type StepType { get; } [IgnoreDataMember] - public bool HasUIElement - { - get { return View.IsNullOrWhiteSpace() == false; } - } - + public bool HasUIElement => View.IsNullOrWhiteSpace() == false; } } diff --git a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs index 06216597cb..64ce51f539 100644 --- a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs +++ b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs @@ -55,9 +55,6 @@ namespace Umbraco.Web.Models [DataMember(Name = "containsMacroConflict")] public bool ContainsMacroConflict { get; set; } - [DataMember(Name = "containsBinaryFileErrors")] - public bool ContainsBinaryFileErrors { get; set; } - [DataMember(Name = "conflictingTemplateAliases")] public IDictionary ConflictingTemplateAliases { get; set; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3d11684c8a..1bd2860781 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1134,14 +1134,9 @@ - - - - - diff --git a/src/Umbraco.Web/_Legacy/PackageActions/PackageHelper.cs b/src/Umbraco.Web/_Legacy/PackageActions/PackageHelper.cs deleted file mode 100644 index 55171c2643..0000000000 --- a/src/Umbraco.Web/_Legacy/PackageActions/PackageHelper.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Xml; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Models; -using Umbraco.Core.Xml; - -namespace Umbraco.Web._Legacy.PackageActions -{ - internal class PackageHelper - { - //Helper method to replace umbraco tags that breaks the xml format.. - public static string ParseToValidXml(ITemplate templateObj, ref bool hasAspNetContentBeginning, string template, bool toValid) - { - string retVal = template; - if (toValid) - { - // test for asp:content as the first part of the design - if (retVal.StartsWith("") + 1); - retVal = retVal.Substring(0, retVal.Length - 14); - } - //shorten empty macro tags.. - retVal = retVal.Replace(">", " />"); - retVal = retVal.Replace(">", " />"); - - retVal = retVal.Replace("", ""); - retVal = retVal.Replace("", ""); - retVal = retVal.Replace("", ""); - - // add asp content element - if (hasAspNetContentBeginning) - { - retVal = MasterPageHelper.GetMasterContentElement(templateObj/*templateObj.MasterTemplate*/) + retVal + ""; - } - } - - return retVal; - } - - public static XmlNode ParseStringToXmlNode(string value) - { - XmlDocument doc = new XmlDocument(); - XmlNode node = XmlHelper.AddTextNode(doc, "error", ""); - - try - { - doc.LoadXml(value); - return doc.SelectSingleNode("."); - } - catch - { - return node; - } - - } - } -} diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs index 09c6df23c4..75614f68aa 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs @@ -1,5 +1,6 @@ using System; using System.Xml; +using System.Xml.Linq; using Umbraco.Core; using Umbraco.Core._Legacy.PackageActions; using Umbraco.Web.Composing; @@ -24,20 +25,20 @@ namespace Umbraco.Web._Legacy.PackageActions /// /// /// true if successfull - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { - string name = xmlData.Attributes["appName"].Value; - string alias = xmlData.Attributes["appAlias"].Value; - string icon = xmlData.Attributes["appIcon"].Value; + string name = xmlData.AttributeValue("appName"); + string alias = xmlData.AttributeValue("appAlias"); + string icon = xmlData.AttributeValue("appIcon"); Current.Services.SectionService.MakeNew(name, alias, icon); return true; } - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { - string alias = xmlData.Attributes["appAlias"].Value; + string alias = xmlData.AttributeValue("appAlias"); var section = Current.Services.SectionService.GetByAlias(alias); if (section != null) { @@ -55,11 +56,6 @@ namespace Umbraco.Web._Legacy.PackageActions } #endregion - - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } - + } } diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs b/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs index 9b3bc5829b..1e2e396d2c 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs @@ -1,5 +1,8 @@ using System; +using System.Linq; using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Xml; @@ -39,30 +42,23 @@ namespace Umbraco.Web._Legacy.PackageActions /// /// /// - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { //this will need a complete section node to work... - if (xmlData.HasChildNodes) + if (xmlData.HasElements) { - string sectionAlias = xmlData.Attributes["dashboardAlias"].Value; + string sectionAlias = xmlData.AttributeValue("dashboardAlias"); string dbConfig = SystemFiles.DashboardConfig; - XmlNode section = xmlData.SelectSingleNode("./section"); - XmlDocument dashboardFile = XmlHelper.OpenAsXmlDocument(dbConfig); + var section = xmlData.Element("section"); + var dashboardFile = XDocument.Load(IOHelper.MapPath(dbConfig)); //don't continue if it already exists - var found = dashboardFile.SelectNodes("//section[@alias='" + sectionAlias + "']"); - if (found == null || found.Count <= 0) + var found = dashboardFile.XPathSelectElements("//section[@alias='" + sectionAlias + "']"); + if (!found.Any()) { - - XmlNode importedSection = dashboardFile.ImportNode(section, true); - - XmlAttribute alias = XmlHelper.AddAttribute(dashboardFile, "alias", sectionAlias); - importedSection.Attributes.Append(alias); - - dashboardFile.DocumentElement.AppendChild(importedSection); - + dashboardFile.Root.Add(section); dashboardFile.Save(IOHelper.MapPath(dbConfig)); } @@ -78,19 +74,18 @@ namespace Umbraco.Web._Legacy.PackageActions return "addDashboardSection"; } - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { - string sectionAlias = xmlData.Attributes["dashboardAlias"].Value; + string sectionAlias = xmlData.AttributeValue("dashboardAlias"); string dbConfig = SystemFiles.DashboardConfig; - XmlDocument dashboardFile = XmlHelper.OpenAsXmlDocument(dbConfig); + var dashboardFile = XDocument.Load(IOHelper.MapPath(dbConfig)); - XmlNode section = dashboardFile.SelectSingleNode("//section [@alias = '" + sectionAlias + "']"); + var section = dashboardFile.XPathSelectElement("//section [@alias = '" + sectionAlias + "']"); if (section != null) { - - dashboardFile.SelectSingleNode("/dashBoard").RemoveChild(section); + section.Remove(); dashboardFile.Save(IOHelper.MapPath(dbConfig)); } @@ -98,11 +93,6 @@ namespace Umbraco.Web._Legacy.PackageActions } #endregion - - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } - + } } diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs b/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs index ac02bc0c33..bcd7d7c52f 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs @@ -1,4 +1,5 @@ using System.Xml; +using System.Xml.Linq; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Xml; @@ -10,42 +11,32 @@ namespace Umbraco.Web._Legacy.PackageActions { #region IPackageAction Members - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { - var hostname = xmlData.Attributes["host"].Value; + var hostname = xmlData.AttributeValue("host"); if (string.IsNullOrEmpty(hostname)) return false; - var xdoc = XmlHelper.OpenAsXmlDocument(SystemFiles.FeedProxyConfig); + var xdoc = XDocument.Load(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); - xdoc.PreserveWhitespace = true; + var insert = true; - var xn = xdoc.SelectSingleNode("//feedProxy"); - if (xn != null) + if (xdoc.Root.HasElements) { - var insert = true; - - if (xn.HasChildNodes) + foreach (var node in xdoc.Root.Elements("allow")) { - foreach (XmlNode node in xn.SelectNodes("//allow")) - { - if (node.Attributes["host"] != null && node.Attributes["host"].Value == hostname) - insert = false; - } - } - - if (insert) - { - var newHostname = XmlHelper.AddTextNode(xdoc, "allow", string.Empty); - newHostname.Attributes.Append(XmlHelper.AddAttribute(xdoc, "host", hostname)); - xn.AppendChild(newHostname); - - xdoc.Save(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); - - return true; + if (node.AttributeValue("host") != null && node.AttributeValue("host") == hostname) + insert = false; } } + if (insert) + { + xdoc.Root.Add(new XElement("allow", new XAttribute("host", hostname))); + xdoc.Save(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); + + return true; + } return false; } @@ -54,47 +45,37 @@ namespace Umbraco.Web._Legacy.PackageActions return "addProxyFeedHost"; } - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { - var hostname = xmlData.Attributes["host"].Value; + var hostname = xmlData.AttributeValue("host"); if (string.IsNullOrEmpty(hostname)) return false; - var xdoc = XmlHelper.OpenAsXmlDocument(SystemFiles.FeedProxyConfig); - xdoc.PreserveWhitespace = true; + var xdoc = XDocument.Load(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); - var xn = xdoc.SelectSingleNode("//feedProxy"); - if (xn != null) + bool inserted = false; + if (xdoc.Root.HasElements) { - bool inserted = false; - if (xn.HasChildNodes) + foreach (var node in xdoc.Root.Elements("allow")) { - foreach (XmlNode node in xn.SelectNodes("//allow")) + if (node.AttributeValue("host") != null && node.AttributeValue("host") == hostname) { - if (node.Attributes["host"] != null && node.Attributes["host"].Value == hostname) - { - xn.RemoveChild(node); - inserted = true; - } + node.Remove(); + inserted = true; } } + } - if (inserted) - { - xdoc.Save(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); - return true; - } + if (inserted) + { + xdoc.Save(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); + return true; } return false; } #endregion - - public XmlNode SampleXml() - { - string sample = ""; - return PackageHelper.ParseStringToXmlNode(sample); - } + } } diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addStringToHtmlElement.cs b/src/Umbraco.Web/_Legacy/PackageActions/addStringToHtmlElement.cs deleted file mode 100644 index 56ebb76980..0000000000 --- a/src/Umbraco.Web/_Legacy/PackageActions/addStringToHtmlElement.cs +++ /dev/null @@ -1,202 +0,0 @@ -using System; -using System.Xml; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Xml; -using Umbraco.Core._Legacy.PackageActions; -using Umbraco.Web.Composing; - -namespace Umbraco.Web._Legacy.PackageActions -{ - /// - /// This class implements the IPackageAction Interface, used to execute code when packages are installed. - /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. - /// addStringToHtmlElement adds a string to specific HTML element in a specific template, and can either append or prepend it. - /// It uses the action xml node to do this, exemple action xml node: - /// - /// The above will add the string "hello world!" to the first html element with the id "newsSection" in the template "news" - /// - public class addStringToHtmlElement : IPackageAction - { - #region IPackageAction Members - - /// - /// Executes the specified package action. - /// - /// Name of the package. - /// The XML data. - /// - /// - /// - /// True if executed successfully - public bool Execute(string packageName, XmlNode xmlData) - { - - - string templateAlias = xmlData.Attributes["templateAlias"].Value; - string htmlElementId = xmlData.Attributes["htmlElementId"].Value; - string position = xmlData.Attributes["position"].Value; - string value = XmlHelper.GetNodeValue(xmlData); - var tmp = Current.Services.FileService.GetTemplate(templateAlias); - - value = MasterPageHelper.EnsureMasterPageSyntax(templateAlias, value); - - _addStringToHtmlElement(tmp, value, htmlElementId, position); - - return true; - } - - - /// - /// Undoes the addStringToHtml Execute() method, by removing the same string from the same template. - /// - /// Name of the package. - /// The XML data. - /// - public bool Undo(string packageName, XmlNode xmlData) - { - string templateAlias = xmlData.Attributes["templateAlias"].Value; - string htmlElementId = xmlData.Attributes["htmlElementId"].Value; - string value = XmlHelper.GetNodeValue(xmlData); - var tmp = Current.Services.FileService.GetTemplate(templateAlias); - - value = MasterPageHelper.EnsureMasterPageSyntax(templateAlias, value); - - _removeStringFromHtmlElement(tmp, value, htmlElementId); - return true; - } - - /// - /// Action alias. - /// - /// - public string Alias() - { - return "addStringToHtmlElement"; - } - - private void _addStringToHtmlElement(ITemplate tmp, string value, string htmlElementId, string position) - { - bool hasAspNetContentBeginning = false; - string design = ""; - string directive = ""; - - if (tmp != null) - { - try - { - XmlDocument templateXml = new XmlDocument(); - templateXml.PreserveWhitespace = true; - - //Make sure that directive is remove before hacked non html4 compatiple replacement action... - design = tmp.Content; - - - splitDesignAndDirective(ref design, ref directive); - - //making sure that the template xml has a root node... - if (string.IsNullOrWhiteSpace(tmp.MasterTemplateAlias) == false) - templateXml.LoadXml(PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, "" + design + "", true)); - else - templateXml.LoadXml(PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, design, true)); - - XmlNode xmlElement = templateXml.SelectSingleNode("//* [@id = '" + htmlElementId + "']"); - - if (xmlElement != null) - { - - if (position == "beginning") - { - xmlElement.InnerXml = "\n" + PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, value, true) + "\n" + xmlElement.InnerXml; - } - else - { - xmlElement.InnerXml = xmlElement.InnerXml + "\n" + PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, value, true) + "\n"; - } - } - - tmp.Content = directive + "\n" + PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, templateXml.OuterXml, false); - Current.Services.FileService.SaveTemplate(tmp); - } - catch (Exception ex) - { - Current.Logger.Error(ex, "An error occurred"); - } - } - else - { - Current.Logger.Debug("template not found"); - } - } - - private void _removeStringFromHtmlElement(ITemplate tmp, string value, string htmlElementId) - { - bool hasAspNetContentBeginning = false; - string design = ""; - string directive = ""; - - - if (tmp != null) - { - try - { - XmlDocument templateXml = new XmlDocument(); - templateXml.PreserveWhitespace = true; - - //Make sure that directive is remove before hacked non html4 compatiple replacement action... - design = tmp.Content; - splitDesignAndDirective(ref design, ref directive); - - //making sure that the template xml has a root node... - if (string.IsNullOrWhiteSpace(tmp.MasterTemplateAlias) == false) - templateXml.LoadXml(PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, "" + design + "", true)); - else - templateXml.LoadXml(PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, design, true)); - - XmlNode xmlElement = templateXml.SelectSingleNode("//* [@id = '" + htmlElementId + "']"); - - - - if (xmlElement != null) - { - string repValue = PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, value, true); - xmlElement.InnerXml = xmlElement.InnerXml.Replace(repValue, ""); - } - - tmp.Content = directive + "\n" + PackageHelper.ParseToValidXml(tmp, ref hasAspNetContentBeginning, templateXml.OuterXml, false); - Current.Services.FileService.SaveTemplate(tmp); - } - catch (Exception ex) - { - Current.Logger.Error(ex, "An error occurred"); - } - } - else - { - Current.Logger.Debug("template not found"); - } - } - - - - private void splitDesignAndDirective(ref string design, ref string directive) - { - if (design.StartsWith("<%@")) - { - directive = design.Substring(0, design.IndexOf("%>") + 2).Trim(Environment.NewLine.ToCharArray()); - design = design.Substring(design.IndexOf("%>") + 3).Trim(Environment.NewLine.ToCharArray()); - } - } - - #endregion - - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } - - } -} diff --git a/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs b/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs index 146925b85f..2ed16e3842 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs @@ -2,6 +2,8 @@ using System.Collections; using System.Linq; using System.Xml; +using System.Xml.Linq; +using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core._Legacy.PackageActions; using Umbraco.Web.Composing; @@ -26,10 +28,10 @@ namespace Umbraco.Web._Legacy.PackageActions /// /// /// Returns true on success - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { - string doctypeName = xmlData.Attributes["documentTypeAlias"].Value; - string parentDoctypeName = xmlData.Attributes["parentDocumentTypeAlias"].Value; + string doctypeName = xmlData.AttributeValue("documentTypeAlias"); + string parentDoctypeName = xmlData.AttributeValue("parentDocumentTypeAlias"); //global::umbraco.cms.businesslogic.ContentType ct = global::umbraco.cms.businesslogic.ContentType.GetByAlias(doctypeName); //global::umbraco.cms.businesslogic.ContentType parentct = global::umbraco.cms.businesslogic.ContentType.GetByAlias(parentDoctypeName); @@ -73,7 +75,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// Name of the package. /// The XML data. /// - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { return true; } @@ -88,11 +90,6 @@ namespace Umbraco.Web._Legacy.PackageActions } #endregion - - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } - + } } diff --git a/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs b/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs index 32147342f6..f4fe17e999 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs @@ -1,5 +1,6 @@ using System; using System.Xml; +using System.Xml.Linq; using Umbraco.Core; using Umbraco.Core._Legacy.PackageActions; using Umbraco.Web.Composing; @@ -23,17 +24,17 @@ namespace Umbraco.Web._Legacy.PackageActions /// /// /// True if executed succesfully - public bool Execute(string packageName, XmlNode xmlData) + public bool Execute(string packageName, XElement xmlData) { - string documentName = xmlData.Attributes["documentName"].Value; + string documentName = xmlData.AttributeValue("documentName"); //global::umbraco.cms.businesslogic.web.Document[] rootDocs = global::umbraco.cms.businesslogic.web.Document.GetRootDocuments(); var rootDocs = Current.Services.ContentService.GetRootContent(); foreach (var rootDoc in rootDocs) { - if (rootDoc.Name.Trim() == documentName.Trim() && rootDoc != null && rootDoc.ContentType != null) + if (rootDoc.Name.Trim() == documentName.Trim() && rootDoc.ContentType != null) { // fixme variants? Current.Services.ContentService.SaveAndPublishBranch(rootDoc, true); @@ -50,7 +51,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// Name of the package. /// The XML data. /// - public bool Undo(string packageName, XmlNode xmlData) + public bool Undo(string packageName, XElement xmlData) { return true; } @@ -64,11 +65,6 @@ namespace Umbraco.Web._Legacy.PackageActions return "publishRootDocument"; } #endregion - - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } - + } } diff --git a/src/Umbraco.Web/_Legacy/PackageActions/removeStringFromTemplate.cs b/src/Umbraco.Web/_Legacy/PackageActions/removeStringFromTemplate.cs deleted file mode 100644 index fd2f40178b..0000000000 --- a/src/Umbraco.Web/_Legacy/PackageActions/removeStringFromTemplate.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Xml; -using Umbraco.Core._Legacy.PackageActions; - -namespace Umbraco.Web._Legacy.PackageActions -{ - public class removeStringFromTemplate : IPackageAction - { - #region IPackageAction Members - - public bool Execute(string packageName, XmlNode xmlData) - { - addStringToHtmlElement ast = new addStringToHtmlElement(); - return ast.Undo(packageName, xmlData); - } - - public string Alias() - { - return "removeStringFromHtmlElement"; - } - - public bool Undo(string packageName, XmlNode xmlData) - { - return true; - } - - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 15a7839227..286f41f61a 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -6,6 +6,8 @@ using System.IO; using System.Linq; using System.Net; using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; using ICSharpCode.SharpZipLib.Zip; using Umbraco.Core; using Umbraco.Core.Composing; @@ -16,8 +18,6 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Services.Implement; -using Umbraco.Core.Xml; -using Umbraco.Web._Legacy.Packager.PackageInstance; using File = System.IO.File; namespace Umbraco.Web._Legacy.Packager @@ -66,16 +66,6 @@ namespace Umbraco.Web._Legacy.Packager public bool ContainsTemplateConflicts { get; private set; } public IDictionary ConflictingTemplateAliases => _conflictingTemplateAliases; - /// - /// Indicates that the package contains assembly reference errors - /// - public bool ContainsBinaryFileErrors { get; private set; } - - /// - /// List each assembly reference error - /// - public List BinaryFileErrors { get; } = new List(); - public bool ContainsStyleSheeConflicts { get; private set; } public IDictionary ConflictingStyleSheetNames => _conflictingStyleSheetNames; @@ -88,9 +78,9 @@ namespace Umbraco.Web._Legacy.Packager public string IconUrl { get; private set; } /// - /// The xmldocument, describing the contents of a package. + /// The xml of the compiled package /// - public XmlDocument Config { get; private set; } + public XDocument Config { get; private set; } /// /// Constructor @@ -108,7 +98,6 @@ namespace Umbraco.Web._Legacy.Packager private void Initialize() { - ContainsBinaryFileErrors = false; ContainsTemplateConflicts = false; ContainsUnsecureFiles = false; ContainsMacroConflict = false; @@ -136,7 +125,6 @@ namespace Umbraco.Web._Legacy.Packager /// public Installer(string name, string version, string url, string license, string licenseUrl, string author, string authorUrl, int requirementsMajor, int requirementsMinor, int requirementsPatch, string readme, string control, RequirementsType requirementsType, string iconUrl) { - ContainsBinaryFileErrors = false; ContainsTemplateConflicts = false; ContainsUnsecureFiles = false; ContainsMacroConflict = false; @@ -209,54 +197,46 @@ namespace Umbraco.Web._Legacy.Packager return Import(inputFile, true); } - public int CreateManifest(string tempDir, Guid guid, string repoGuid) + public int CreateManifest(Guid guid) { //This is the new improved install rutine, which chops up the process into 3 steps, creating the manifest, moving files, and finally handling umb objects - var packName = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name")); - var packAuthor = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/name")); - var packAuthorUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/website")); - var packVersion = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/version")); - var packReadme = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); - var packLicense = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license ")); - var packUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/url ")); - var iconUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/iconUrl")); - var enableSkins = false; - var skinRepoGuid = ""; + var parser = new CompiledPackageXmlParser(); + var def = parser.ToCompiledPackage(Config); - if (Config.DocumentElement.SelectSingleNode("/umbPackage/enableSkins") != null) + //create a new entry in the installedPackages.config + var installedPackage = new PackageDefinition { - var skinNode = Config.DocumentElement.SelectSingleNode("/umbPackage/enableSkins"); - enableSkins = bool.Parse(XmlHelper.GetNodeValue(skinNode)); - if (skinNode.Attributes["repository"] != null && string.IsNullOrEmpty(skinNode.Attributes["repository"].Value) == false) - skinRepoGuid = skinNode.Attributes["repository"].Value; - } + Author = def.Author, + AuthorUrl = def.AuthorUrl, + Control = def.Control, + IconUrl = def.IconUrl, + License = def.License, + LicenseUrl = def.LicenseUrl, + Name = def.Name, + Readme = def.Readme, + UmbracoVersion = def.UmbracoVersion, + Url = def.Url, + Version = def.Version, + PackageId = guid + }; - //Create a new package instance to record all the installed package adds - this is the same format as the created packages has. - //save the package meta data - var insPack = InstalledPackage.MakeNew(packName); - insPack.Data.Author = packAuthor; - insPack.Data.AuthorUrl = packAuthorUrl; - insPack.Data.Version = packVersion; - insPack.Data.Readme = packReadme; - insPack.Data.License = packLicense; - insPack.Data.Url = packUrl; - insPack.Data.IconUrl = iconUrl; + if (!Current.Services.PackagingService.SaveInstalledPackage(installedPackage)) + throw new InvalidOperationException("Could not save package definition"); - insPack.Data.PackageId = guid; //the package unique key. - insPack.Save(); - - return insPack.Data.Id; + return installedPackage.Id; } public void InstallFiles(int packageId, string tempDir) { + var parser = new CompiledPackageXmlParser(); + using (Current.ProfilingLogger.DebugDuration( "Installing package files for package id " + packageId + " into temp folder " + tempDir, "Package file installation complete for package id " + packageId)) { //retrieve the manifest to continue installation - var insPack = InstalledPackage.GetById(packageId); + var insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); //TODO: Depending on some files, some files should be installed differently. //i.e. if stylsheets should probably be installed via business logic, media items should probably use the media IFileSystem! @@ -265,13 +245,15 @@ namespace Umbraco.Web._Legacy.Packager //string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath; string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; + var def = parser.ToCompiledPackage(Config); + try { - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) + foreach (var f in def.Files) { - var destPath = GetFileName(basePath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - var sourceFile = GetFileName(tempDir, XmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); - var destFile = GetFileName(destPath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + var destPath = GetFileName(basePath, f.OriginalPath); + var sourceFile = GetFileName(tempDir, f.UniqueFileName); + var destFile = GetFileName(destPath, f.OriginalName); // Create the destination directory if it doesn't exist if (Directory.Exists(destPath) == false) @@ -300,14 +282,14 @@ namespace Umbraco.Web._Legacy.Packager File.Copy(sourceFile, destFile); //PPH log file install - insPack.Data.Files.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")) + "/" + XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + insPack.Files.Add(f.OriginalPath.EnsureEndsWith('/') + f.OriginalName); } // Once we're done copying, remove all the files - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) + foreach (var f in def.Files) { - var sourceFile = GetFileName(tempDir, XmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); + var sourceFile = GetFileName(tempDir, f.UniqueFileName); if (File.Exists(sourceFile)) File.Delete(sourceFile); } @@ -323,10 +305,10 @@ namespace Umbraco.Web._Legacy.Packager { Current.Services.AuditService.Add(AuditType.PackagerInstall, _currentUserId, - -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Data.Name, insPack.Data.PackageId)); + -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Name, insPack.PackageId)); } - insPack.Save(); + Current.Services.PackagingService.SaveInstalledPackage(insPack); } } @@ -336,11 +318,11 @@ namespace Umbraco.Web._Legacy.Packager "Installing business logic for package id " + packageId + " into temp folder " + tempDir, "Package business logic installation complete for package id " + packageId)) { - InstalledPackage insPack; + PackageDefinition insPack; try { //retrieve the manifest to continue installation - insPack = InstalledPackage.GetById(packageId); + insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); //bool saveNeeded = false; // Get current user, with a fallback @@ -348,9 +330,7 @@ namespace Umbraco.Web._Legacy.Packager //TODO: Get rid of this entire class! Until then all packages will be installed by the admin user - - //Xml as XElement which is used with the new PackagingService - var rootElement = Config.DocumentElement.GetXElement(); + var rootElement = Config.Root; var packagingService = Current.Services.PackagingService; //Perhaps it would have been a good idea to put the following into methods eh?!? @@ -362,7 +342,7 @@ namespace Umbraco.Web._Legacy.Packager var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement, currentUser.Id); foreach (var dataTypeDefinition in dataTypeDefinitions) { - insPack.Data.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); + insPack.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); } } #endregion @@ -373,7 +353,7 @@ namespace Umbraco.Web._Legacy.Packager { var insertedLanguages = packagingService.ImportLanguages(languageItemsElement); foreach(var x in insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))) - insPack.Data.Languages.Add(x); + insPack.Languages.Add(x); } #endregion @@ -384,7 +364,7 @@ namespace Umbraco.Web._Legacy.Packager { var insertedDictionaryItems = packagingService.ImportDictionaryItems(dictionaryItemsElement); foreach (var x in insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))) - insPack.Data.DictionaryItems.Add(x); + insPack.DictionaryItems.Add(x); } #endregion @@ -394,7 +374,7 @@ namespace Umbraco.Web._Legacy.Packager { var insertedMacros = packagingService.ImportMacros(macroItemsElement); foreach (var x in insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))) - insPack.Data.Macros.Add(x); + insPack.Macros.Add(x); } #endregion @@ -406,7 +386,7 @@ namespace Umbraco.Web._Legacy.Packager var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); foreach (var template in templates) { - insPack.Data.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); + insPack.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); } } #endregion @@ -423,32 +403,35 @@ namespace Umbraco.Web._Legacy.Packager var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); foreach (var contentType in contentTypes) { - insPack.Data.DocumentTypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); + insPack.DocumentTypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); //saveNeeded = true; } } #endregion #region Stylesheets - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) + foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) { - //StyleSheet s = StyleSheet.Import(n, currentUser); + string stylesheetName = n.Element("Name")?.Value; + if (stylesheetName.IsNullOrWhiteSpace()) continue; - - string stylesheetName = XmlHelper.GetNodeValue(n.SelectSingleNode("Name")); - //StyleSheet s = GetByName(stylesheetName); var s = Current.Services.FileService.GetStylesheetByName(stylesheetName); if (s == null) { - s = new Stylesheet(XmlHelper.GetNodeValue(n.SelectSingleNode("FileName"))) { Content = XmlHelper.GetNodeValue(n.SelectSingleNode("Content")) }; + var fileName = n.Element("FileName")?.Value; + if (fileName == null) continue; + var content = n.Element("Content")?.Value; + if (content == null) continue; + + s = new Stylesheet(fileName) { Content = content }; Current.Services.FileService.SaveStylesheet(s); } - foreach (XmlNode prop in n.SelectNodes("Properties/Property")) + foreach (var prop in n.XPathSelectElements("Properties/Property")) { - string alias = XmlHelper.GetNodeValue(prop.SelectSingleNode("Alias")); + string alias = prop.Element("Alias")?.Value; var sp = s.Properties.SingleOrDefault(p => p != null && p.Alias == alias); - string name = XmlHelper.GetNodeValue(prop.SelectSingleNode("Name")); + string name = prop.Element("Name")?.Value; if (sp == null) { //sp = StylesheetProperty.MakeNew( @@ -472,7 +455,7 @@ namespace Umbraco.Web._Legacy.Packager } } sp.Alias = alias; - sp.Value = XmlHelper.GetNodeValue(prop.SelectSingleNode("Value")); + sp.Value = prop.Element("Value")?.Value; } //s.saveCssToFile(); Current.Services.FileService.SaveStylesheet(s); @@ -480,7 +463,7 @@ namespace Umbraco.Web._Legacy.Packager - insPack.Data.Stylesheets.Add(s.Id.ToString(CultureInfo.InvariantCulture)); + insPack.Stylesheets.Add(s.Id.ToString(CultureInfo.InvariantCulture)); //saveNeeded = true; } @@ -493,33 +476,34 @@ namespace Umbraco.Web._Legacy.Packager { var content = packagingService.ImportContent(documentElement, -1, currentUser.Id); var firstContentItem = content.First(); - insPack.Data.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); + insPack.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); } #endregion #region Package Actions - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Actions/Action")) + foreach (var n in Config.Root.XPathSelectElements("Actions/Action")) { - if (n.Attributes["undo"] == null || n.Attributes["undo"].Value == "true") + var undo = n.AttributeValue("undo"); + if (undo == null || undo == "true") { - insPack.Data.Actions += n.OuterXml; + insPack.Actions += n.ToString(); } //Run the actions tagged only for 'install' + var runat = n.AttributeValue("runat"); - if (n.Attributes["runat"] != null && n.Attributes["runat"].Value == "install") + if (runat != null && runat == "install") { - var alias = n.Attributes["alias"] != null ? n.Attributes["alias"].Value : ""; - + var alias = n.AttributeValue("alias"); if (alias.IsNullOrWhiteSpace() == false) { - Current.PackageActionRunner.RunPackageAction(insPack.Data.Name, alias, n); + Current.PackageActionRunner.RunPackageAction(insPack.Name, alias, n); } } } #endregion - insPack.Save(); + Current.Services.PackagingService.SaveInstalledPackage(insPack); } catch (Exception ex) { @@ -527,7 +511,6 @@ namespace Umbraco.Web._Legacy.Packager throw; } - OnPackageBusinessLogicInstalled(insPack); OnPackageInstalled(insPack); } } @@ -551,40 +534,35 @@ namespace Umbraco.Web._Legacy.Packager /// The folder to which the contents of the package is extracted public void LoadConfig(string tempDir) { - Config = new XmlDocument(); - Config.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); + Config = XDocument.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); - Name = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name").FirstChild.Value; - Version = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/version").FirstChild.Value; - Url = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/url").FirstChild.Value; - License = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license").FirstChild.Value; - LicenseUrl = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license").Attributes.GetNamedItem("url").Value; + var parser = new CompiledPackageXmlParser(); + var def = parser.ToCompiledPackage(Config); - RequirementsMajor = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/major").FirstChild.Value); - RequirementsMinor = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/minor").FirstChild.Value); - RequirementsPatch = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/patch").FirstChild.Value); + Name = def.Name; + Version = def.Version; + Url = def.Url; + License = def.License; + LicenseUrl = def.LicenseUrl; - var reqNode = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements"); - RequirementsType = reqNode != null && reqNode.Attributes != null && reqNode.Attributes["type"] != null - ? Enum.Parse(reqNode.Attributes["type"].Value, true) - : RequirementsType.Legacy; - var iconNode = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/iconUrl"); - if (iconNode != null && iconNode.FirstChild != null) - { - IconUrl = iconNode.FirstChild.Value; - } - - Author = Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/name").FirstChild.Value; - AuthorUrl = Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/website").FirstChild.Value; + RequirementsMajor = def.UmbracoVersion.Major; + RequirementsMinor = def.UmbracoVersion.Minor; + RequirementsPatch = def.UmbracoVersion.Build; + RequirementsType = def.UmbracoVersionRequirementsType; + IconUrl = def.IconUrl; + Author = def.Author; + AuthorUrl = def.AuthorUrl; + ReadMe = def.Readme; + Control = def.Control; var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; var dllBinFiles = new List(); - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) + foreach (var f in def.Files) { var badFile = false; - var destPath = GetFileName(basePath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - var orgName = XmlHelper.GetNodeValue(n.SelectSingleNode("orgName")); + var destPath = GetFileName(basePath, f.OriginalPath); + var orgName = f.OriginalName; var destFile = GetFileName(destPath, orgName); if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) @@ -606,7 +584,7 @@ namespace Umbraco.Web._Legacy.Packager if (badFile) { ContainsUnsecureFiles = true; - UnsecureFiles.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + UnsecureFiles.Add(f.OriginalName); } } @@ -614,9 +592,9 @@ namespace Umbraco.Web._Legacy.Packager //this will check for existing macros with the same alias //since we will not overwrite on import it's a good idea to inform the user what will be overwritten - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//macro")) + foreach (var n in Config.Root.XPathSelectElements("//macro")) { - var alias = n.SelectSingleNode("alias").InnerText; + var alias = n.Element("alias")?.Value; if (!string.IsNullOrEmpty(alias)) { var m = Current.Services.MacroService.GetByAlias(alias); @@ -631,9 +609,9 @@ namespace Umbraco.Web._Legacy.Packager } } - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Templates/Template")) + foreach (var n in Config.Root.XPathSelectElements("Templates/Template")) { - var alias = n.SelectSingleNode("Alias").InnerText; + var alias = n.Element("Alias")?.Value; if (!string.IsNullOrEmpty(alias)) { var t = Current.Services.FileService.GetTemplate(alias); @@ -648,9 +626,9 @@ namespace Umbraco.Web._Legacy.Packager } } - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) + foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) { - var alias = n.SelectSingleNode("Name").InnerText; + var alias = n.Element("Name")?.Value; if (!string.IsNullOrEmpty(alias)) { var s = Current.Services.FileService.GetStylesheetByName(alias); @@ -665,17 +643,7 @@ namespace Umbraco.Web._Legacy.Packager } } - var readmeNode = Config.DocumentElement.SelectSingleNode("/umbPackage/info/readme"); - if (readmeNode != null) - { - ReadMe = XmlHelper.GetNodeValue(readmeNode); - } - - var controlNode = Config.DocumentElement.SelectSingleNode("/umbPackage/control"); - if (controlNode != null) - { - Control = XmlHelper.GetNodeValue(controlNode); - } + } /// @@ -815,15 +783,8 @@ namespace Umbraco.Web._Legacy.Packager #endregion - internal static event EventHandler PackageBusinessLogicInstalled; - private static void OnPackageBusinessLogicInstalled(InstalledPackage e) - { - var handler = PackageBusinessLogicInstalled; - handler?.Invoke(null, e); - } - - private void OnPackageInstalled(InstalledPackage insPack) + private void OnPackageInstalled(PackageDefinition insPack) { // getting an InstallationSummary for sending to the PackagingService.ImportedPackage event var fileService = Current.Services.FileService; @@ -832,12 +793,10 @@ namespace Umbraco.Web._Legacy.Packager var dataTypeService = Current.Services.DataTypeService; var localizationService = Current.Services.LocalizationService; - var installationSummary = insPack.GetInstallationSummary(contentTypeService, dataTypeService, fileService, localizationService, macroService); + var installationSummary = InstallationSummary.FromPackageDefinition(insPack, contentTypeService, dataTypeService, fileService, localizationService, macroService); installationSummary.PackageInstalled = true; - var meta = insPack.GetMetaData(); - - var args = new ImportPackageEventArgs(installationSummary, meta, false); + var args = new ImportPackageEventArgs(installationSummary, insPack, false); PackagingService.OnImportedPackage(args); } } diff --git a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs b/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs deleted file mode 100644 index e5af44b747..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/PackageInstance/InstalledPackage.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Composing; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Services; - -namespace Umbraco.Web._Legacy.Packager.PackageInstance -{ - public class InstalledPackage - { - - private int _saveHitCount = 0; - - public static InstalledPackage GetById(int id) - { - InstalledPackage pack = new InstalledPackage(); - pack.Data = data.Package(id, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - return pack; - } - - public static InstalledPackage MakeNew(string name) - { - InstalledPackage pack = new InstalledPackage(); - pack.Data = data.MakeNew(name, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - return pack; - } - - public void Save() - { -#if DEBUG - _saveHitCount++; - Current.Logger.Info("The InstalledPackage class save method has been hit {Total} times.", _saveHitCount); -#endif - data.Save(this.Data, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - } - - public static List GetAllInstalledPackages() - { - - List val = new List(); - - foreach (Core.Models.Packaging.PackageDefinition pack in data.GetAllPackages(IOHelper.MapPath(Settings.InstalledPackagesSettings))) - { - InstalledPackage insPackage = new InstalledPackage(); - insPackage.Data = pack; - val.Add(insPackage); - } - - return val; - } - - public Core.Models.Packaging.PackageDefinition Data { get; set; } - - public void Delete(int userId) - { - Current.Services.AuditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", string.Format("Package '{0}' uninstalled. Package guid: {1}", Data.Name, Data.PackageId)); - Delete(); - } - - public void Delete() - { - data.Delete(this.Data.Id, IOHelper.MapPath(Settings.InstalledPackagesSettings)); - } - - - - /// - /// Used internally for creating an InstallationSummary (used in new PackagingService) representation of this InstalledPackage object. - /// - /// - /// - /// - /// - /// - /// - internal InstallationSummary GetInstallationSummary(IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService) - { - var macros = TryGetIntegerIds(Data.Macros).Select(macroService.GetById).ToList(); - var templates = TryGetIntegerIds(Data.Templates).Select(fileService.GetTemplate).ToList(); - var contentTypes = TryGetIntegerIds(Data.DocumentTypes).Select(contentTypeService.Get).ToList(); // fixme - media types? - var dataTypes = TryGetIntegerIds(Data.DataTypes).Select(dataTypeService.GetDataType).ToList(); - var dictionaryItems = TryGetIntegerIds(Data.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList(); - var languages = TryGetIntegerIds(Data.Languages).Select(localizationService.GetLanguageById).ToList(); - - for (var i = 0; i < Data.Files.Count; i++) - { - var filePath = Data.Files[i]; - Data.Files[i] = filePath.GetRelativePath(); - } - - return new InstallationSummary - { - ContentTypesInstalled = contentTypes, - DataTypesInstalled = dataTypes, - DictionaryItemsInstalled = dictionaryItems, - FilesInstalled = Data.Files, - LanguagesInstalled = languages, - MacrosInstalled = macros, - MetaData = GetMetaData(), - TemplatesInstalled = templates, - }; - } - - internal MetaData GetMetaData() - { - return new MetaData() - { - AuthorName = Data.Author, - AuthorUrl = Data.AuthorUrl, - Control = Data.LoadControl, - License = Data.License, - LicenseUrl = Data.LicenseUrl, - Name = Data.Name, - Readme = Data.Readme, - Url = Data.Url, - Version = Data.Version - }; - } - - private static IEnumerable TryGetIntegerIds(IEnumerable ids) - { - var intIds = new List(); - foreach (var id in ids) - { - int parsed; - if (int.TryParse(id, out parsed)) - intIds.Add(parsed); - } - return intIds; - } - } -} diff --git a/src/Umbraco.Web/_Legacy/Packager/data.cs b/src/Umbraco.Web/_Legacy/Packager/data.cs deleted file mode 100644 index 51f0799689..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/data.cs +++ /dev/null @@ -1,374 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Xml; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Xml; - -namespace Umbraco.Web._Legacy.Packager -{ - /// - /// This is the xml data for installed packages. This is not the same xml as a pckage format! - /// - public class data - { - public static XmlDocument Source { get; private set; } - - public static void Reload(string dataSource) - { - //do some error checking and create the folders/files if they don't exist - if (!File.Exists(dataSource)) - { - if (!Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages))) - { - Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - } - - using (var sw = File.CreateText(dataSource)) - { - sw.Write($@"{Environment.NewLine}{Environment.NewLine}"); - sw.Flush(); - } - - } - - if (Source == null) - { - Source = new XmlDocument(); - } - - //error checking here - if (File.Exists(dataSource)) - { - var isEmpty = false; - using (var sr = new StreamReader(dataSource)) - { - if (sr.ReadToEnd().IsNullOrWhiteSpace()) - { - isEmpty = true; - } - } - if (isEmpty) - { - File.WriteAllText(dataSource, @""); - } - } - - Source.Load(dataSource); - } - - public static XmlNode GetFromId(int Id, string dataSource, bool reload) - { - if (reload) - Reload(dataSource); - - return Source.SelectSingleNode("/packages/package [@id = '" + Id.ToString().ToUpper() + "']"); - } - - public static XmlNode GetFromGuid(string guid, string dataSource, bool reload) - { - if (reload) - Reload(dataSource); - - return Source.SelectSingleNode("/packages/package [@packageGuid = '" + guid + "']"); - } - - public static Core.Models.Packaging.PackageDefinition MakeNew(string name, string dataSource) - { - Reload(dataSource); - - int maxId = 1; - // Find max id - foreach (XmlNode n in Source.SelectNodes("packages/package")) - { - if (int.Parse(n.Attributes.GetNamedItem("id").Value) >= maxId) - maxId = int.Parse(n.Attributes.GetNamedItem("id").Value) + 1; - } - - XmlElement instance = Source.CreateElement("package"); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "id", maxId.ToString())); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "version", "")); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "url", "")); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "name", name)); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "folder", Guid.NewGuid().ToString())); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "packagePath", "")); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "repositoryGuid", "")); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "iconUrl", "")); - //set to current version - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "umbVersion", UmbracoVersion.Current.ToString(3))); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "packageGuid", Guid.NewGuid().ToString())); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "hasUpdate", "false")); - - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "enableSkins", "false")); - instance.Attributes.Append(XmlHelper.AddAttribute(Source, "skinRepoGuid", "")); - - XmlElement license = Source.CreateElement("license"); - license.InnerText = "MIT License"; - license.Attributes.Append(XmlHelper.AddAttribute(Source, "url", "http://opensource.org/licenses/MIT")); - instance.AppendChild(license); - - XmlElement author = Source.CreateElement("author"); - author.InnerText = ""; - author.Attributes.Append(XmlHelper.AddAttribute(Source, "url", "")); - instance.AppendChild(author); - - instance.AppendChild(XmlHelper.AddTextNode(Source, "readme", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "actions", "")); - - instance.AppendChild(XmlHelper.AddTextNode(Source, "datatypes", "")); - - XmlElement content = Source.CreateElement("content"); - content.InnerText = ""; - content.Attributes.Append(XmlHelper.AddAttribute(Source, "nodeId", "")); - content.Attributes.Append(XmlHelper.AddAttribute(Source, "loadChildNodes", "false")); - instance.AppendChild(content); - - instance.AppendChild(XmlHelper.AddTextNode(Source, "templates", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "stylesheets", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "documentTypes", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "macros", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "files", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "languages", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "dictionaryitems", "")); - instance.AppendChild(XmlHelper.AddTextNode(Source, "loadcontrol", "")); - - Source.SelectSingleNode("packages").AppendChild(instance); - Source.Save(dataSource); - var retVal = data.Package(maxId, dataSource); - - return retVal; - } - - public static Core.Models.Packaging.PackageDefinition Package(int id, string datasource) - { - return ConvertXmlToPackage(GetFromId(id, datasource, true)); - } - - public static Core.Models.Packaging.PackageDefinition Package(string guid, string datasource) - { - XmlNode node = GetFromGuid(guid, datasource, true); - if (node != null) - return ConvertXmlToPackage(node); - else - return new Core.Models.Packaging.PackageDefinition(); - } - - public static List GetAllPackages(string dataSource) - { - Reload(dataSource); - XmlNodeList nList = data.Source.SelectNodes("packages/package"); - - List retVal = new List(); - - for (int i = 0; i < nList.Count; i++) - { - try - { - retVal.Add(ConvertXmlToPackage(nList[i])); - } - catch (Exception ex) - { - Current.Logger.Error(ex, "An error occurred in GetAllPackages"); - } - } - - return retVal; - } - - private static Core.Models.Packaging.PackageDefinition ConvertXmlToPackage(XmlNode n) - { - Core.Models.Packaging.PackageDefinition retVal = new Core.Models.Packaging.PackageDefinition(); - - if (n != null) - { - retVal.Id = int.Parse(SafeAttribute("id", n)); - retVal.Name = SafeAttribute("name", n); - retVal.FolderId = Guid.Parse(SafeAttribute("folder", n)); - retVal.PackagePath = SafeAttribute("packagePath", n); - retVal.Version = SafeAttribute("version", n); - retVal.Url = SafeAttribute("url", n); - retVal.PackageId = Guid.Parse(SafeAttribute("packageGuid", n)); - - retVal.IconUrl = SafeAttribute("iconUrl", n); - var umbVersion = SafeAttribute("umbVersion", n); - Version parsedVersion; - if (umbVersion.IsNullOrWhiteSpace() == false && Version.TryParse(umbVersion, out parsedVersion)) - { - retVal.UmbracoVersion = parsedVersion; - } - - retVal.License = SafeNodeValue(n.SelectSingleNode("license")); - retVal.LicenseUrl = n.SelectSingleNode("license").Attributes.GetNamedItem("url").Value; - - retVal.Author = SafeNodeValue(n.SelectSingleNode("author")); - retVal.AuthorUrl = SafeAttribute("url", n.SelectSingleNode("author")); - - retVal.Readme = SafeNodeValue(n.SelectSingleNode("readme")); - retVal.Actions = SafeNodeInnerXml(n.SelectSingleNode("actions")); - - retVal.ContentNodeId = SafeAttribute("nodeId", n.SelectSingleNode("content")); - retVal.ContentLoadChildNodes = bool.Parse(SafeAttribute("loadChildNodes", n.SelectSingleNode("content"))); - - retVal.Macros = new List(SafeNodeValue(n.SelectSingleNode("macros")).Trim(',').Split(',')); - retVal.Macros = new List(SafeNodeValue(n.SelectSingleNode("macros")).Trim(',').Split(',')); - retVal.Templates = new List(SafeNodeValue(n.SelectSingleNode("templates")).Trim(',').Split(',')); - retVal.Stylesheets = new List(SafeNodeValue(n.SelectSingleNode("stylesheets")).Trim(',').Split(',')); - retVal.DocumentTypes = new List(SafeNodeValue(n.SelectSingleNode("documentTypes")).Trim(',').Split(',')); - retVal.Languages = new List(SafeNodeValue(n.SelectSingleNode("languages")).Trim(',').Split(',')); - retVal.DictionaryItems = new List(SafeNodeValue(n.SelectSingleNode("dictionaryitems")).Trim(',').Split(',')); - retVal.DataTypes = new List(SafeNodeValue(n.SelectSingleNode("datatypes")).Trim(',').Split(',')); - - XmlNodeList xmlFiles = n.SelectNodes("files/file"); - retVal.Files = new List(); - - for (int i = 0; i < xmlFiles.Count; i++) - retVal.Files.Add(xmlFiles[i].InnerText); - - retVal.LoadControl = SafeNodeValue(n.SelectSingleNode("loadcontrol")); - } - - return retVal; - } - - public static void Delete(int Id, string dataSource) - { - Reload(dataSource); - // Remove physical xml file if any - //PackageInstance p = new PackageInstance(Id); - - //TODO DELETE PACKAGE FOLDER... - //p.Folder - - XmlNode n = data.GetFromId(Id, dataSource, true); - if (n != null) - { - data.Source.SelectSingleNode("/packages").RemoveChild(n); - data.Source.Save(dataSource); - } - - } - - - public static void Save(Core.Models.Packaging.PackageDefinition package, string dataSource) - { - Reload(dataSource); - var xmlDef = GetFromId(package.Id, dataSource, false); - XmlHelper.SetAttribute(Source, xmlDef, "name", package.Name); - XmlHelper.SetAttribute(Source, xmlDef, "version", package.Version); - XmlHelper.SetAttribute(Source, xmlDef, "url", package.Url); - XmlHelper.SetAttribute(Source, xmlDef, "packagePath", package.PackagePath); - XmlHelper.SetAttribute(Source, xmlDef, "packageGuid", package.PackageId.ToString()); - XmlHelper.SetAttribute(Source, xmlDef, "iconUrl", package.IconUrl); - if (package.UmbracoVersion != null) - XmlHelper.SetAttribute(Source, xmlDef, "umbVersion", package.UmbracoVersion.ToString(3)); - - var licenseNode = xmlDef.SelectSingleNode("license"); - if (licenseNode == null) - { - licenseNode = Source.CreateElement("license"); - xmlDef.AppendChild(licenseNode); - } - licenseNode.InnerText = package.License; - XmlHelper.SetAttribute(Source, licenseNode, "url", package.LicenseUrl); - - var authorNode = xmlDef.SelectSingleNode("author"); - if (authorNode == null) - { - authorNode = Source.CreateElement("author"); - xmlDef.AppendChild(authorNode); - } - authorNode.InnerText = package.Author; - XmlHelper.SetAttribute(Source, authorNode, "url", package.AuthorUrl); - - XmlHelper.SetCDataNode(Source, xmlDef, "readme", package.Readme); - XmlHelper.SetInnerXmlNode(Source, xmlDef, "actions", package.Actions); - - var contentNode = xmlDef.SelectSingleNode("content"); - if (contentNode == null) - { - contentNode = Source.CreateElement("content"); - xmlDef.AppendChild(contentNode); - } - XmlHelper.SetAttribute(Source, contentNode, "nodeId", package.ContentNodeId); - XmlHelper.SetAttribute(Source, contentNode, "loadChildNodes", package.ContentLoadChildNodes.ToString()); - - XmlHelper.SetTextNode(Source, xmlDef, "macros", JoinList(package.Macros, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "templates", JoinList(package.Templates, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "stylesheets", JoinList(package.Stylesheets, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "documentTypes", JoinList(package.DocumentTypes, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "languages", JoinList(package.Languages, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "dictionaryitems", JoinList(package.DictionaryItems, ',')); - XmlHelper.SetTextNode(Source, xmlDef, "datatypes", JoinList(package.DataTypes, ',')); - - var filesNode = xmlDef.SelectSingleNode("files"); - if (filesNode == null) - { - filesNode = Source.CreateElement("files"); - xmlDef.AppendChild(filesNode); - } - filesNode.InnerXml = ""; - - foreach (var fileStr in package.Files) - { - if (string.IsNullOrWhiteSpace(fileStr) == false) - filesNode.AppendChild(XmlHelper.AddTextNode(Source, "file", fileStr)); - } - - XmlHelper.SetTextNode(Source, xmlDef, "loadcontrol", package.LoadControl); - - Source.Save(dataSource); - } - - - - private static string SafeAttribute(string name, XmlNode n) - { - return n.Attributes == null || n.Attributes[name] == null ? string.Empty : n.Attributes[name].Value; - } - - private static string SafeNodeValue(XmlNode n) - { - try - { - return XmlHelper.GetNodeValue(n); - } - catch - { - return string.Empty; - } - } - - private static string SafeNodeInnerXml(XmlNode n) - { - try - { - return n.InnerXml; - } - catch - { - return string.Empty; - } - } - - - private static string JoinList(IList list, char seperator) - { - string retVal = ""; - foreach (string str in list) - { - retVal += str + seperator; - } - - return retVal.Trim(seperator); - } - - public data() - { - - } - } -} From 29390a3624bb275d829da5d12af0eeb424b3fb75 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 11 Jan 2019 15:15:59 +0100 Subject: [PATCH 071/223] Fixes string to int conversion error --- .../PropertyEditors/MultiNodePickerConfigurationTreeSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs index ffedf6c7dc..65115afc63 100644 --- a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs +++ b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs @@ -15,6 +15,6 @@ namespace Umbraco.Web.PropertyEditors public string StartNodeQuery {get;set;} [JsonProperty("id")] - public int? StartNodeId {get;set;} + public string StartNodeId {get;set;} } } From 8f41fe8d3840cccb5235ba632a6d69a2f8efbcc4 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 11 Jan 2019 15:17:29 +0100 Subject: [PATCH 072/223] Fixes MNTP only being able to open contentPicker --- .../contentpicker/contentpicker.controller.js | 45 ++++++++++++------- .../contentpicker/contentpicker.html | 2 +- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index af3ce50609..e084d7116a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -52,18 +52,18 @@ function contentPickerController($scope, entityResource, editorState, iconHelper } function startWatch() { - + //due to the way angular-sortable works, it needs to update a model, we don't want it to update renderModel since renderModel //is updated based on changes to model.value so if we bound angular-sortable to that and put a watch on it we'd end up in a //infinite loop. Instead we have a custom array model for angular-sortable and we'll watch that which we'll use to sync the model.value //which in turn will sync the renderModel. - $scope.$watchCollection("sortableModel", function(newVal, oldVal) { + $scope.$watchCollection("sortableModel", function (newVal, oldVal) { $scope.model.value = newVal.join(); }); //if the underlying model changes, update the view model, this ensures that the view is always consistent with the underlying //model if it changes (i.e. based on server updates, or if used in split view, etc...) - $scope.$watch("model.value", function(newVal, oldVal) { + $scope.$watch("model.value", function (newVal, oldVal) { if (newVal !== oldVal) { syncRenderModel(); } @@ -195,25 +195,38 @@ function contentPickerController($scope, entityResource, editorState, iconHelper } //dialog - $scope.openContentPicker = function () { - $scope.contentPicker = dialogOptions; + $scope.openCurrentPicker = function () { + $scope.currentPicker = dialogOptions; - $scope.contentPicker.submit = function (model) { + $scope.currentPicker.submit = function (model) { if (angular.isArray(model.selection)) { _.each(model.selection, function (item, i) { $scope.add(item); }); - angularHelper.getCurrentForm($scope).$setDirty(); + angularHelper.getCurrentForm($scope).$setDirty(); } angularHelper.getCurrentForm($scope).$setDirty(); editorService.close(); } - $scope.contentPicker.close = function () { + $scope.currentPicker.close = function () { editorService.close(); } - editorService.contentPicker($scope.contentPicker); + //open the correct editor based on the entity type + switch (entityType) { + case "Document": + editorService.contentPicker($scope.currentPicker); + break; + case "Media": + editorService.mediaPicker($scope.currentPicker); + break; + case "Member": + editorService.memberGroupPicker($scope.currentPicker); + break; + + default: + } }; @@ -256,7 +269,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper $scope.model.value = null; }; - $scope.openContentEditor = function (node)  { + $scope.openContentEditor = function (node) { var contentEditor = { id: node.id, submit: function (model) { @@ -296,7 +309,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper if (valueIds.length > 0) { //need to determine which items we already have loaded - var renderModelIds = _.map($scope.renderModel, function(d) { + var renderModelIds = _.map($scope.renderModel, function (d) { return $scope.model.config.idType === "udi" ? d.udi : d.id; }); @@ -313,11 +326,11 @@ function contentPickerController($scope, entityResource, editorState, iconHelper var missingIds = _.difference(valueIds, renderModelIds); if (missingIds.length > 0) { - return entityResource.getByIds(missingIds, entityType).then(function(data) { + return entityResource.getByIds(missingIds, entityType).then(function (data) { _.each(valueIds, - function(id, i) { - var entity = _.find(data, function(d) { + function (id, i) { + var entity = _.find(data, function (d) { return $scope.model.config.idType === "udi" ? (d.udi == id) : (d.id == id); }); @@ -330,7 +343,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper if (doValidation) { validate(); } - + setSortingState($scope.renderModel); return $q.when(true); }); @@ -342,7 +355,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper $scope.renderModel = []; for (var k = 0; k < valueIds.length; k++) { var id = valueIds[k]; - var found = _.find(current, function(d) { + var found = _.find(current, function (d) { return $scope.model.config.idType === "udi" ? (d.udi == id) : (d.id == id); }); if (found) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html index 2f1303077c..a589cf8947 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html @@ -22,7 +22,7 @@ Add From 18c90c532574ae4630b3f58e2080471b6d9a3084 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 14 Jan 2019 14:28:00 +1100 Subject: [PATCH 073/223] Package file installation logic all migrated and tests are running, now to do the package data installation --- .../Composing/Composers/ServicesComposer.cs | 10 + .../Models/Packaging/CompiledPackage.cs | 23 +- .../Models/Packaging/InstallationSummary.cs | 70 +- .../Models/Packaging/PackageDefinition.cs | 31 + .../Models/Packaging/PreInstallWarnings.cs | 15 +- .../Packaging/CompiledPackageXmlParser.cs | 150 ++ .../Packaging/ConflictingPackageData.cs | 61 +- .../Packaging/IConflictingPackageData.cs | 13 - .../Packaging/IPackageExtraction.cs | 62 - .../Packaging/IPackageInstallation.cs | 34 +- .../Packaging/PackageDefinitionXmlParser.cs | 54 - .../Packaging/PackageExtraction.cs | 76 +- .../Packaging/PackageFileInstallation.cs | 63 + .../Packaging/PackageInstallation.cs | 574 ++----- .../Services/IPackagingService.cs | 36 +- .../Services/Implement/PackagingService.cs | 56 +- src/Umbraco.Core/Umbraco.Core.csproj | 6 +- .../CreatedPackagesRepositoryTests.cs | 8 +- .../Packaging/PackageExtractionTests.cs | 4 +- .../Packaging/PackageInstallationTest.cs | 151 +- .../Services/PackagingServiceTests.cs | 49 +- .../views/packages/views/install-local.html | 2 +- .../src/views/packages/views/repo.html | 2 +- src/Umbraco.Web/Composing/Current.cs | 4 +- .../Editors/PackageInstallController.cs | 72 +- .../Controllers/InstallPackageController.cs | 58 +- .../InstallSteps/StarterKitCleanupStep.cs | 16 +- .../InstallSteps/StarterKitDownloadStep.cs | 31 +- .../InstallSteps/StarterKitInstallStep.cs | 24 +- .../Install/Models/InstallPackageModel.cs | 6 +- .../Models/LocalPackageInstallModel.cs | 19 +- src/Umbraco.Web/Models/PackageInstallModel.cs | 3 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 - src/Umbraco.Web/_Legacy/Packager/Installer.cs | 1471 ++++++++--------- src/Umbraco.Web/_Legacy/Packager/Settings.cs | 13 - 35 files changed, 1534 insertions(+), 1734 deletions(-) create mode 100644 src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs delete mode 100644 src/Umbraco.Core/Packaging/IConflictingPackageData.cs delete mode 100644 src/Umbraco.Core/Packaging/IPackageExtraction.cs create mode 100644 src/Umbraco.Core/Packaging/PackageFileInstallation.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/Settings.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 98f239de3b..ac8f4beeb0 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -61,8 +61,18 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(); + composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(factory => CreatePackageRepository(factory, "createdPackages.config")); composition.RegisterUnique(factory => CreatePackageRepository(factory, "installedPackages.config")); + composition.RegisterUnique(); + var appRoot = new DirectoryInfo(IOHelper.GetRootDirectorySafe()); + composition.RegisterUnique(factory => //factory required because we need to pass in a string path + new PackageInstallation( + factory.GetInstance(), factory.GetInstance(), + factory.GetInstance(), + SystemDirectories.Packages, + appRoot, appRoot)); //TODO: These are replaced in the web project - we need to declare them so that // something is wired up, just not sure this is very nice but will work for now. diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index cb3fbd7eee..96159d1bbf 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Xml.Linq; namespace Umbraco.Core.Models.Packaging { @@ -9,32 +10,31 @@ namespace Umbraco.Core.Models.Packaging /// public class CompiledPackage : IPackageInfo { + public string PackageFileName { get; set; } + public string Name { get; set; } - public string Version { get; set; } - public string Url { get; set; } - public string License { get; set; } - public string LicenseUrl { get; set; } - public Version UmbracoVersion { get; set; } - public RequirementsType UmbracoVersionRequirementsType { get; set; } - public string Author { get; set; } - public string AuthorUrl { get; set; } - public string Readme { get; set; } - public string Control { get; set; } - public string IconUrl { get; set; } + public string Actions { get; set; } //fixme: Should we make this strongly typed to IEnumerable ? + + public PreInstallWarnings Warnings { get; set; } = new PreInstallWarnings(); + public List Files { get; set; } = new List(); + public IEnumerable Macros { get; set; } //fixme: make strongly typed + public IEnumerable Templates { get; set; } //fixme: make strongly typed + public IEnumerable Stylesheets { get; set; } //fixme: make strongly typed + } public class CompiledPackageFile @@ -42,6 +42,7 @@ namespace Umbraco.Core.Models.Packaging public string OriginalPath { get; set; } public string UniqueFileName { get; set; } public string OriginalName { get; set; } + } diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index ddecf53653..1405259da2 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -24,44 +24,44 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable Actions { get; set; } = Enumerable.Empty(); public bool PackageInstalled { get; set; } - public static InstallationSummary FromPackageDefinition(PackageDefinition def, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService) - { - var macros = TryGetIntegerIds(def.Macros).Select(macroService.GetById).ToList(); - var templates = TryGetIntegerIds(def.Templates).Select(fileService.GetTemplate).ToList(); - var contentTypes = TryGetIntegerIds(def.DocumentTypes).Select(contentTypeService.Get).ToList(); // fixme - media types? - var dataTypes = TryGetIntegerIds(def.DataTypes).Select(dataTypeService.GetDataType).ToList(); - var dictionaryItems = TryGetIntegerIds(def.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList(); - var languages = TryGetIntegerIds(def.Languages).Select(localizationService.GetLanguageById).ToList(); + //public static InstallationSummary FromPackageDefinition(PackageDefinition def, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService) + //{ + // var macros = TryGetIntegerIds(def.Macros).Select(macroService.GetById).ToList(); + // var templates = TryGetIntegerIds(def.Templates).Select(fileService.GetTemplate).ToList(); + // var contentTypes = TryGetIntegerIds(def.DocumentTypes).Select(contentTypeService.Get).ToList(); // fixme - media types? + // var dataTypes = TryGetIntegerIds(def.DataTypes).Select(dataTypeService.GetDataType).ToList(); + // var dictionaryItems = TryGetIntegerIds(def.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList(); + // var languages = TryGetIntegerIds(def.Languages).Select(localizationService.GetLanguageById).ToList(); - for (var i = 0; i < def.Files.Count; i++) - { - var filePath = def.Files[i]; - def.Files[i] = filePath.GetRelativePath(); - } + // for (var i = 0; i < def.Files.Count; i++) + // { + // var filePath = def.Files[i]; + // def.Files[i] = filePath.GetRelativePath(); + // } - return new InstallationSummary - { - ContentTypesInstalled = contentTypes, - DataTypesInstalled = dataTypes, - DictionaryItemsInstalled = dictionaryItems, - FilesInstalled = def.Files, - LanguagesInstalled = languages, - MacrosInstalled = macros, - MetaData = def, - TemplatesInstalled = templates, - }; - } + // return new InstallationSummary + // { + // ContentTypesInstalled = contentTypes, + // DataTypesInstalled = dataTypes, + // DictionaryItemsInstalled = dictionaryItems, + // FilesInstalled = def.Files, + // LanguagesInstalled = languages, + // MacrosInstalled = macros, + // MetaData = def, + // TemplatesInstalled = templates, + // }; + //} - private static IEnumerable TryGetIntegerIds(IEnumerable ids) - { - var intIds = new List(); - foreach (var id in ids) - { - if (int.TryParse(id, out var parsed)) - intIds.Add(parsed); - } - return intIds; - } + //private static IEnumerable TryGetIntegerIds(IEnumerable ids) + //{ + // var intIds = new List(); + // foreach (var id in ids) + // { + // if (int.TryParse(id, out var parsed)) + // intIds.Add(parsed); + // } + // return intIds; + //} } } diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index 65e26419f0..56a316ff81 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Runtime.Serialization; namespace Umbraco.Core.Models.Packaging @@ -9,6 +10,35 @@ namespace Umbraco.Core.Models.Packaging [DataContract(Name = "packageInstance")] public class PackageDefinition : IPackageInfo { + /// + /// Converts a model to a model + /// + /// + /// + /// + /// This is used only for conversions and will not 'get' a PackageDefinition from the repository with a valid ID + /// + internal static PackageDefinition FromCompiledPackage(CompiledPackage compiled) + { + return new PackageDefinition + { + Actions = compiled.Actions, + Author = compiled.Author, + AuthorUrl = compiled.AuthorUrl, + Control = compiled.Control, + IconUrl = compiled.IconUrl, + License = compiled.License, + LicenseUrl = compiled.LicenseUrl, + Name = compiled.Name, + Readme = compiled.Readme, + UmbracoVersion = compiled.UmbracoVersion, + Url = compiled.Url, + Version = compiled.Version, + //fixme: Is OriginalPath correct here? + Files = compiled.Files.Select(x => x.OriginalPath).ToList() + }; + } + [DataMember(Name = "id")] public int Id { get; set; } @@ -24,6 +54,7 @@ namespace Umbraco.Core.Models.Packaging [Url] public string Url { get; set; } = string.Empty; + //fixme: remove this /// /// This is a generated GUID which is used to determine a temporary folder name for processing the package /// diff --git a/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs b/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs index 5850e2321c..18b63ced88 100644 --- a/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs +++ b/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs @@ -1,17 +1,16 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.Serialization; namespace Umbraco.Core.Models.Packaging { - [Serializable] - [DataContract(IsReference = true)] - internal class PreInstallWarnings + public class PreInstallWarnings { - public KeyValuePair[] UnsecureFiles { get; set; } - public KeyValuePair[] FilesReplaced { get; set; } - public IEnumerable ConflictingMacroAliases { get; set; } - public IEnumerable ConflictingTemplateAliases { get; set; } - public IEnumerable ConflictingStylesheetNames { get; set; } + public IEnumerable UnsecureFiles { get; set; } = Enumerable.Empty(); + public IEnumerable FilesReplaced { get; set; } = Enumerable.Empty(); + public IEnumerable ConflictingMacros { get; set; } = Enumerable.Empty(); + public IEnumerable ConflictingTemplates { get; set; } = Enumerable.Empty(); + public IEnumerable ConflictingStylesheets { get; set; } = Enumerable.Empty(); } } diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs new file mode 100644 index 0000000000..44dbded5d2 --- /dev/null +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Umbraco.Core.IO; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Packaging; +using File = System.IO.File; + +namespace Umbraco.Core.Packaging +{ + /// + /// Parses the xml document contained in a compiled (zip) Umbraco package + /// + internal class CompiledPackageXmlParser + { + private readonly ConflictingPackageData _conflictingPackageData; + + public CompiledPackageXmlParser(ConflictingPackageData conflictingPackageData) + { + _conflictingPackageData = conflictingPackageData; + } + + public CompiledPackage ToCompiledPackage(XDocument xml, string packageFileName, string applicationRootFolder) + { + if (xml == null) throw new ArgumentNullException(nameof(xml)); + if (xml.Root == null) throw new ArgumentException(nameof(xml), "The xml document is invalid"); + if (xml.Root.Name != Constants.Packaging.UmbPackageNodeName) throw new FormatException("The xml document is invalid"); + + var info = xml.Root.Element("info"); + if (info == null) throw new FormatException("The xml document is invalid"); + var package = info.Element("package"); + if (package == null) throw new FormatException("The xml document is invalid"); + var author = info.Element("author"); + if (author == null) throw new FormatException("The xml document is invalid"); + var requirements = package.Element("requirements"); + if (requirements == null) throw new FormatException("The xml document is invalid"); + + var def = new CompiledPackage + { + PackageFileName = packageFileName, + Name = package.Element("name")?.Value, + Author = author.Element("name")?.Value, + AuthorUrl = author.Element("website")?.Value, + Version = package.Element("version")?.Value, + Readme = info.Element("readme")?.Value, + License = package.Element("license")?.Value, + LicenseUrl = package.Element("license")?.AttributeValue("url"), + Url = package.Element("url")?.Value, + IconUrl = package.Element("iconUrl")?.Value, + UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), + UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type")), + Control = package.Element("control")?.Value, + Actions = xml.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value + + Files = xml.Root.Element("files")?.Elements("file")?.Select(x => new CompiledPackageFile + { + UniqueFileName = x.Element("guid")?.Value, + OriginalName = x.Element("orgName")?.Value, + OriginalPath = x.Element("orgPath")?.Value + }).ToList() ?? new List(), + + Macros = xml.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), + Templates = xml.Element("Templates")?.Elements("Template") ?? Enumerable.Empty(), + Stylesheets = xml.Element("Stylesheets")?.Elements("styleSheet") ?? Enumerable.Empty(), + + }; + + def.Warnings = GetPreInstallWarnings(def, applicationRootFolder); + + return def; + } + + private PreInstallWarnings GetPreInstallWarnings(CompiledPackage package, string applicationRootFolder) + { + var sourceDestination = ExtractSourceDestinationFileInformation(package.Files); + + var installWarnings = new PreInstallWarnings + { + ConflictingMacros = _conflictingPackageData.FindConflictingMacros(package.Macros), + ConflictingTemplates = _conflictingPackageData.FindConflictingTemplates(package.Templates), + ConflictingStylesheets = _conflictingPackageData.FindConflictingStylesheets(package.Stylesheets), + UnsecureFiles = FindUnsecureFiles(sourceDestination), + FilesReplaced = FindFilesToBeReplaced(sourceDestination, applicationRootFolder) + }; + + return installWarnings; + } + + /// + /// Returns a tuple of the zip file's unique file name and it's application relative path + /// + /// + /// + public (string packageUniqueFile, string appRelativePath)[] ExtractSourceDestinationFileInformation(IEnumerable packageFiles) + { + return packageFiles + .Select(e => + { + var fileName = PrepareAsFilePathElement(e.OriginalName); + var relativeDir = UpdatePathPlaceholders(PrepareAsFilePathElement(e.OriginalPath)); + var relativePath = Path.Combine(relativeDir, fileName); + return (e.UniqueFileName, relativePath); + }).ToArray(); + } + + private IEnumerable FindFilesToBeReplaced(IEnumerable<(string packageUniqueFile, string appRelativePath)> sourceDestination, string applicationRootFolder) + { + return sourceDestination.Where(sd => File.Exists(Path.Combine(applicationRootFolder, sd.appRelativePath))) + .Select(x => x.appRelativePath) + .ToArray(); + } + + private IEnumerable FindUnsecureFiles(IEnumerable<(string packageUniqueFile, string appRelativePath)> sourceDestinationPair) + { + return sourceDestinationPair.Where(sd => IsFileDestinationUnsecure(sd.appRelativePath)) + .Select(x => x.appRelativePath) + .ToList(); + } + + private bool IsFileDestinationUnsecure(string destination) + { + var unsecureDirNames = new[] { "bin", "app_code" }; + if (unsecureDirNames.Any(ud => destination.StartsWith(ud, StringComparison.InvariantCultureIgnoreCase))) + return true; + + string extension = Path.GetExtension(destination); + return extension != null && extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase); + } + + private static string PrepareAsFilePathElement(string pathElement) + { + return pathElement.TrimStart(new[] { '\\', '/', '~' }).Replace("/", "\\"); + } + + //fixme: This is duplicated in the parser + public static string UpdatePathPlaceholders(string path) + { + if (path.Contains("[$")) + { + //this is experimental and undocumented... + path = path.Replace("[$UMBRACO]", SystemDirectories.Umbraco); + path = path.Replace("[$CONFIG]", SystemDirectories.Config); + path = path.Replace("[$DATA]", SystemDirectories.Data); + } + return path; + } + } +} diff --git a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs index b0424067bf..401d3b6a85 100644 --- a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs +++ b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs @@ -7,82 +7,53 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Packaging { - internal class ConflictingPackageData : IConflictingPackageData + internal class ConflictingPackageData { private readonly IMacroService _macroService; private readonly IFileService _fileService; - public ConflictingPackageData(IMacroService macroService, - IFileService fileService) + public ConflictingPackageData(IMacroService macroService, IFileService fileService) { - if (fileService != null) _fileService = fileService; - else throw new ArgumentNullException("fileService"); - if (macroService != null) _macroService = macroService; - else throw new ArgumentNullException("macroService"); + _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); + _macroService = macroService ?? throw new ArgumentNullException(nameof(macroService)); } - public IEnumerable FindConflictingStylesheets(XElement stylesheetNotes) + public IEnumerable FindConflictingStylesheets(IEnumerable stylesheetNodes) { - if (string.Equals(Constants.Packaging.StylesheetsNodeName, stylesheetNotes.Name.LocalName) == false) - { - throw new ArgumentException("the root element must be \"" + Constants.Packaging.StylesheetsNodeName + "\"", "stylesheetNotes"); - } - - return stylesheetNotes.Elements(Constants.Packaging.StylesheetNodeName) + return stylesheetNodes .Select(n => { - XElement xElement = n.Element(Constants.Packaging.NameNodeName); + var xElement = n.Element(Constants.Packaging.NameNodeName); if (xElement == null) - { - throw new ArgumentException("Missing \"" + Constants.Packaging.NameNodeName + "\" element", - "stylesheetNotes"); - } + throw new FormatException($"Missing \"{Constants.Packaging.NameNodeName}\" element"); return _fileService.GetStylesheetByName(xElement.Value) as IFile; }) .Where(v => v != null); } - public IEnumerable FindConflictingTemplates(XElement templateNotes) + public IEnumerable FindConflictingTemplates(IEnumerable templateNodes) { - if (string.Equals(Constants.Packaging.TemplatesNodeName, templateNotes.Name.LocalName) == false) - { - throw new ArgumentException("Node must be a \"" + Constants.Packaging.TemplatesNodeName + "\" node", - "templateNotes"); - } - - return templateNotes.Elements(Constants.Packaging.TemplateNodeName) + return templateNodes .Select(n => { - XElement xElement = n.Element(Constants.Packaging.AliasNodeNameCapital) ?? n.Element(Constants.Packaging.AliasNodeNameSmall); + var xElement = n.Element(Constants.Packaging.AliasNodeNameCapital) ?? n.Element(Constants.Packaging.AliasNodeNameSmall); if (xElement == null) - { - throw new ArgumentException("missing a \"" + Constants.Packaging.AliasNodeNameCapital + "\" element", - "templateNotes"); - } + throw new FormatException($"missing a \"{Constants.Packaging.AliasNodeNameCapital}\" element"); return _fileService.GetTemplate(xElement.Value); }) .Where(v => v != null); } - public IEnumerable FindConflictingMacros(XElement macroNodes) + public IEnumerable FindConflictingMacros(IEnumerable macroNodes) { - if (string.Equals(Constants.Packaging.MacrosNodeName, macroNodes.Name.LocalName) == false) - { - throw new ArgumentException("Node must be a \"" + Constants.Packaging.MacrosNodeName + "\" node", - "macroNodes"); - } - - return macroNodes.Elements(Constants.Packaging.MacroNodeName) + return macroNodes .Select(n => { - XElement xElement = n.Element(Constants.Packaging.AliasNodeNameSmall) ?? n.Element(Constants.Packaging.AliasNodeNameCapital); + var xElement = n.Element(Constants.Packaging.AliasNodeNameSmall) ?? n.Element(Constants.Packaging.AliasNodeNameCapital); if (xElement == null) - { - throw new ArgumentException(string.Format("missing a \"{0}\" element in {0} element", Constants.Packaging.AliasNodeNameSmall), - "macroNodes"); - } + throw new FormatException($"missing a \"{Constants.Packaging.AliasNodeNameSmall}\" element in {Constants.Packaging.AliasNodeNameSmall} element"); return _macroService.GetByAlias(xElement.Value); }) diff --git a/src/Umbraco.Core/Packaging/IConflictingPackageData.cs b/src/Umbraco.Core/Packaging/IConflictingPackageData.cs deleted file mode 100644 index 12f3e8f8a4..0000000000 --- a/src/Umbraco.Core/Packaging/IConflictingPackageData.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Xml.Linq; -using Umbraco.Core.Models; - -namespace Umbraco.Core.Packaging -{ - internal interface IConflictingPackageData - { - IEnumerable FindConflictingStylesheets(XElement stylesheetNotes); - IEnumerable FindConflictingTemplates(XElement templateNotes); - IEnumerable FindConflictingMacros(XElement macroNodes); - } -} diff --git a/src/Umbraco.Core/Packaging/IPackageExtraction.cs b/src/Umbraco.Core/Packaging/IPackageExtraction.cs deleted file mode 100644 index 02e98dc539..0000000000 --- a/src/Umbraco.Core/Packaging/IPackageExtraction.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Packaging -{ - /// - /// Used to access an umbraco package (zip) file - /// Remeber that filenames must be unique - /// use "FindDubletFileNames" for sanitycheck - /// - internal interface IPackageExtraction - { - /// - /// Returns the content of the file with the given filename - /// - /// Full path to the umbraco package file - /// filename of the file for wich to get the text content - /// this is the relative directory for the location of the file in the package - /// I dont know why umbraco packages contains directories in the first place?? - /// text content of the file - string ReadTextFileFromArchive(string packageFilePath, string fileToRead, out string directoryInPackage); - - /// - /// Copies a file from package to given destination - /// - /// Full path to the ubraco package file - /// filename of the file to copy - /// destination path (including destination filename) - /// True a file was overwritten - void CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath); - - /// - /// Copies a file from package to given destination - /// - /// Full path to the ubraco package file - /// Key: Source file in package. Value: Destination path inclusive file name - void CopyFilesFromArchive(string packageFilePath, IEnumerable> sourceDestination); - - /// - /// Check if given list of files can be found in the package - /// - /// Full path to the umbraco package file - /// a list of files you would like to find in the package - /// a subset if any of the files in "expectedFiles" that could not be found in the package - IEnumerable FindMissingFiles(string packageFilePath, IEnumerable expectedFiles); - - - /// - /// Sanitycheck - should return en empty collection if package is valid - /// - /// Full path to the umbraco package file - /// list of files that are found more than ones (accross directories) in the package - IEnumerable FindDubletFileNames(string packageFilePath); - - /// - /// Reads the given files from archive and returns them as a collection of byte arrays - /// - /// - /// - /// - IEnumerable ReadFilesFromArchive(string packageFilePath, IEnumerable filesToGet); - } -} diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index e8950390e4..8ef3546c3d 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -1,15 +1,35 @@ -using System.Xml.Linq; +using System.Collections.Generic; +using System.Xml.Linq; using Umbraco.Core.Models.Packaging; namespace Umbraco.Core.Packaging { internal interface IPackageInstallation { - //fixme: The reason why this isn't used currently is because package installation needs to be done in phases since - // there are app domain reboots involved so a single method cannot be used. This needs to either be split into several - // methods or return an object with a callback to proceed to the next step. - InstallationSummary InstallPackage(string packageFilePath, int userId); - IPackageInfo GetMetaData(string packageFilePath); - PreInstallWarnings GetPreInstallWarnings(string packageFilePath); + + /// + /// Installs a packages data and entities + /// + /// + /// + /// + /// + InstallationSummary InstallPackageData(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId); + + /// + /// Installs a packages files + /// + /// + /// + /// + /// + IEnumerable InstallPackageFiles(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId); + + /// + /// Reads the package (zip) file and returns the model + /// + /// + /// + CompiledPackage ReadPackage(string packageFileName); } } diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 6f3e4a3603..9a996d201f 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -8,60 +8,6 @@ using Umbraco.Core.Models.Packaging; namespace Umbraco.Core.Packaging { - /// - /// Parses the xml document contained in a compiled (zip) Umbraco package - /// - public class CompiledPackageXmlParser - { - public CompiledPackageXmlParser() - { - - } - - public CompiledPackage ToCompiledPackage(XDocument xml) - { - if (xml == null) throw new ArgumentNullException(nameof(xml)); - if (xml.Root == null) throw new ArgumentException(nameof(xml), "The xml document is invalid"); - if (xml.Root.Name != Constants.Packaging.UmbPackageNodeName) throw new FormatException("The xml document is invalid"); - - var info = xml.Root.Element("info"); - if (info == null) throw new FormatException("The xml document is invalid"); - var package = xml.Element("package"); - if (package == null) throw new FormatException("The xml document is invalid"); - var author = package.Element("author"); - if (author == null) throw new FormatException("The xml document is invalid"); - var requirements = package.Element("requirements"); - if (requirements == null) throw new FormatException("The xml document is invalid"); - - var def = new CompiledPackage - { - Name = package.Element("name")?.Value, - Author = author.Element("name")?.Value, - AuthorUrl = author.Element("website")?.Value, - Version = package.Element("version")?.Value, - Readme = info.Element("readme")?.Value, - License = package.Element("license")?.Value, - LicenseUrl = package.Element("license")?.AttributeValue("url"), - Url = package.Element("url")?.Value, - IconUrl = package.Element("iconUrl")?.Value, - UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), - UmbracoVersionRequirementsType = Enum.Parse(requirements.AttributeValue("type")), - Control = package.Element("control")?.Value, - - Files = xml.Root.Element("files")?.Elements("files")?.Select(x => new CompiledPackageFile - { - UniqueFileName = x.Element("guid")?.Value, - OriginalName = x.Element("orgPath")?.Value, - OriginalPath = x.Element("orgName")?.Value - }).ToList() ?? new List(), - - }; - - return def; - } - - } - /// /// Converts a to and from XML /// diff --git a/src/Umbraco.Core/Packaging/PackageExtraction.cs b/src/Umbraco.Core/Packaging/PackageExtraction.cs index cc3c394732..48093da45f 100644 --- a/src/Umbraco.Core/Packaging/PackageExtraction.cs +++ b/src/Umbraco.Core/Packaging/PackageExtraction.cs @@ -6,15 +6,15 @@ using System.IO.Compression; namespace Umbraco.Core.Packaging { - internal class PackageExtraction : IPackageExtraction + internal class PackageExtraction { - public string ReadTextFileFromArchive(string packageFilePath, string fileToRead, out string directoryInPackage) + public string ReadTextFileFromArchive(FileInfo packageFile, string fileToRead, out string directoryInPackage) { string retVal = null; bool fileFound = false; string foundDir = null; - ReadZipfileEntries(packageFilePath, entry => + ReadZipfileEntries(packageFile, entry => { string fileName = Path.GetFileName(entry.Name); @@ -36,55 +36,50 @@ namespace Umbraco.Core.Packaging if (fileFound == false) { directoryInPackage = null; - throw new FileNotFoundException(string.Format("Could not find file in package {0}", packageFilePath), fileToRead); + throw new FileNotFoundException($"Could not find file in package {packageFile}", fileToRead); } directoryInPackage = foundDir; return retVal; } - private static void CheckPackageExists(string packageFilePath) + private static void CheckPackageExists(FileInfo packageFile) { - if (string.IsNullOrEmpty(packageFilePath)) - { - throw new ArgumentNullException("packageFilePath"); - } + if (packageFile == null) throw new ArgumentNullException(nameof(packageFile)); + + if (!packageFile.Exists) + throw new ArgumentException($"Package file: {packageFile} could not be found"); - if (File.Exists(packageFilePath) == false) - { - if (File.Exists(packageFilePath) == false) - throw new ArgumentException(string.Format("Package file: {0} could not be found", packageFilePath)); - } - - string extension = Path.GetExtension(packageFilePath).ToLower(); + var extension = packageFile.Extension; var alowedExtension = new[] { ".umb", ".zip" }; // Check if the file is a valid package - if (alowedExtension.All(ae => ae.Equals(extension) == false)) + if (alowedExtension.All(ae => ae.InvariantEquals(extension) == false)) { - throw new ArgumentException( - string.Format("Error - file isn't a package. only extentions: \"{0}\" is allowed", string.Join(", ", alowedExtension))); + throw new ArgumentException("Error - file isn't a package. only extentions: \"{string.Join(", ", alowedExtension)}\" is allowed"); } } - public void CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath) + public void CopyFileFromArchive(FileInfo packageFile, string fileInPackageName, string destinationfilePath) { - CopyFilesFromArchive(packageFilePath, new[]{new KeyValuePair(fileInPackageName, destinationfilePath) } ); + CopyFilesFromArchive(packageFile, new[] {(fileInPackageName, destinationfilePath)}); } - public void CopyFilesFromArchive(string packageFilePath, IEnumerable> sourceDestination) + public void CopyFilesFromArchive(FileInfo packageFile, IEnumerable<(string packageUniqueFile, string appAbsolutePath)> sourceDestination) { - var d = sourceDestination.ToDictionary(k => k.Key.ToLower(), v => v.Value); + var d = sourceDestination.ToDictionary(k => k.packageUniqueFile.ToLower(), v => v.appAbsolutePath); - ReadZipfileEntries(packageFilePath, entry => + ReadZipfileEntries(packageFile, entry => { - string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower(); + var fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower(); if (fileName == string.Empty) { return true; } - string destination; - if (string.IsNullOrEmpty(fileName) == false && d.TryGetValue(fileName, out destination)) + if (string.IsNullOrEmpty(fileName) == false && d.TryGetValue(fileName, out var destination)) { + //ensure the dir exists + Directory.CreateDirectory(Path.GetDirectoryName(destination)); + using (var streamWriter = File.Open(destination, FileMode.Create)) using (var entryStream = entry.Open()) { @@ -99,15 +94,15 @@ namespace Umbraco.Core.Packaging if (d.Any()) { - throw new ArgumentException(string.Format("The following source file(s): \"{0}\" could not be found in archive: \"{1}\"", string.Join("\", \"",d.Keys), packageFilePath)); + throw new ArgumentException(string.Format("The following source file(s): \"{0}\" could not be found in archive: \"{1}\"", string.Join("\", \"",d.Keys), packageFile)); } } - public IEnumerable FindMissingFiles(string packageFilePath, IEnumerable expectedFiles) + public IEnumerable FindMissingFiles(FileInfo packageFile, IEnumerable expectedFiles) { var retVal = expectedFiles.ToList(); - ReadZipfileEntries(packageFilePath, zipEntry => + ReadZipfileEntries(packageFile, zipEntry => { string fileName = Path.GetFileName(zipEntry.Name); @@ -121,17 +116,16 @@ namespace Umbraco.Core.Packaging } - public IEnumerable FindDubletFileNames(string packageFilePath) + public IEnumerable FindDuplicateFileNames(FileInfo packageFile) { var dictionary = new Dictionary>(); - ReadZipfileEntries(packageFilePath, entry => + ReadZipfileEntries(packageFile, entry => { - string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower(); + var fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower(); - List list; - if (dictionary.TryGetValue(fileName, out list) == false) + if (dictionary.TryGetValue(fileName, out var list) == false) { list = new List(); dictionary.Add(fileName, list); @@ -145,13 +139,13 @@ namespace Umbraco.Core.Packaging return dictionary.Values.Where(v => v.Count > 1).SelectMany(v => v); } - public IEnumerable ReadFilesFromArchive(string packageFilePath, IEnumerable filesToGet) + public IEnumerable ReadFilesFromArchive(FileInfo packageFile, IEnumerable filesToGet) { - CheckPackageExists(packageFilePath); + CheckPackageExists(packageFile); var files = new HashSet(filesToGet.Select(f => f.ToLowerInvariant())); - using (var fs = File.OpenRead(packageFilePath)) + using (var fs = packageFile.OpenRead()) using (var zipArchive = new ZipArchive(fs)) { foreach (var zipEntry in zipArchive.Entries) @@ -172,11 +166,11 @@ namespace Umbraco.Core.Packaging } } - private void ReadZipfileEntries(string packageFilePath, Func entryFunc, bool skipsDirectories = true) + private void ReadZipfileEntries(FileInfo packageFile, Func entryFunc, bool skipsDirectories = true) { - CheckPackageExists(packageFilePath); + CheckPackageExists(packageFile); - using (var fs = File.OpenRead(packageFilePath)) + using (var fs = packageFile.OpenRead()) using (var zipArchive = new ZipArchive(fs)) { foreach (var zipEntry in zipArchive.Entries) diff --git a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs new file mode 100644 index 0000000000..55b8bdc63e --- /dev/null +++ b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Services; +using File = System.IO.File; + +namespace Umbraco.Core.Packaging +{ + /// + /// Installs package files + /// + internal class PackageFileInstallation + { + private readonly CompiledPackageXmlParser _parser; + private readonly IProfilingLogger _logger; + private readonly PackageExtraction _packageExtraction; + + public PackageFileInstallation(CompiledPackageXmlParser parser, IProfilingLogger logger) + { + _parser = parser; + _logger = logger; + _packageExtraction = new PackageExtraction(); + } + + /// + /// Returns a list of all installed file paths + /// + /// + /// + /// + /// The absolute path of where to extract the package files (normally the application root) + /// + /// + public IEnumerable InstallFiles(CompiledPackage compiledPackage, FileInfo packageFile, string targetRootFolder) + { + using (_logger.DebugDuration( + "Installing package files for package " + compiledPackage.Name, + "Package file installation complete for package " + compiledPackage.Name)) + { + var sourceAndRelativeDest = _parser.ExtractSourceDestinationFileInformation(compiledPackage.Files); + var sourceAndAbsDest = AppendRootToDestination(targetRootFolder, sourceAndRelativeDest); + + _packageExtraction.CopyFilesFromArchive(packageFile, sourceAndAbsDest); + + return sourceAndRelativeDest.Select(sd => sd.appRelativePath).ToArray(); + } + } + + private static IEnumerable<(string packageUniqueFile, string appAbsolutePath)> AppendRootToDestination(string applicationRootFolder, IEnumerable<(string packageUniqueFile, string appRelativePath)> sourceDestination) + { + return + sourceDestination.Select( + sd => (sd.packageUniqueFile, Path.Combine(applicationRootFolder, sd.appRelativePath))).ToArray(); + } + } +} diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 6c9cd57451..5dd88e5a56 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -1,262 +1,221 @@ using System; using System.Collections.Generic; -using System.Data; using System.IO; using System.Linq; using System.Xml.Linq; -using System.Xml.XPath; -using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services; -using File = System.IO.File; namespace Umbraco.Core.Packaging { + internal class PackageInstallation : IPackageInstallation { - private readonly IFileService _fileService; - private readonly IMacroService _macroService; private readonly IPackagingService _packagingService; - private IConflictingPackageData _conflictingPackageData; - private readonly IPackageExtraction _packageExtraction; - private string _fullPathToRoot; - - public PackageInstallation(IPackagingService packagingService, IMacroService macroService, - IFileService fileService, IPackageExtraction packageExtraction) - : this(packagingService, macroService, fileService, packageExtraction, IOHelper.GetRootDirectorySafe()) - {} - - public PackageInstallation(IPackagingService packagingService, IMacroService macroService, - IFileService fileService, IPackageExtraction packageExtraction, string fullPathToRoot) - { - if (packageExtraction != null) _packageExtraction = packageExtraction; - else throw new ArgumentNullException("packageExtraction"); - - if (macroService != null) _macroService = macroService; - else throw new ArgumentNullException("macroService"); - - if (fileService != null) _fileService = fileService; - else throw new ArgumentNullException("fileService"); - - if (packagingService != null) _packagingService = packagingService; - else throw new ArgumentNullException("packagingService"); - - _fullPathToRoot = fullPathToRoot; - } - - public IConflictingPackageData ConflictingPackageData - { - private get - { - return _conflictingPackageData ?? - (_conflictingPackageData = new ConflictingPackageData(_macroService, _fileService)); - } - set - { - if (_conflictingPackageData != null) - { - throw new PropertyConstraintException("This property already have a value"); - } - _conflictingPackageData = value; - } - } - - public string FullPathToRoot - { - private get { return _fullPathToRoot; } - set - { - - if (_fullPathToRoot != null) - { - throw new PropertyConstraintException("This property already have a value"); - } - - _fullPathToRoot = value; - } - } - - public IPackageInfo GetMetaData(string packageFilePath) - { - try - { - XElement rootElement = GetConfigXmlElement(packageFilePath); - return GetMetaData(rootElement); - } - catch (Exception e) - { - throw new Exception("Error reading " + packageFilePath, e); - } - } - - public PreInstallWarnings GetPreInstallWarnings(string packageFilePath) - { - try - { - XElement rootElement = GetConfigXmlElement(packageFilePath); - return GetPreInstallWarnings(rootElement); - } - catch (Exception e) - { - throw new Exception("Error reading " + packageFilePath, e); - } - } - - public InstallationSummary InstallPackage(string packageFile, int userId) - { - XElement dataTypes; - XElement languages; - XElement dictionaryItems; - XElement macroes; - XElement files; - XElement templates; - XElement documentTypes; - XElement styleSheets; - XElement documentSet; - XElement documents; - XElement actions; - IPackageInfo metaData; - InstallationSummary installationSummary; - - try - { - XElement rootElement = GetConfigXmlElement(packageFile); - PackageSupportedCheck(rootElement); - PackageStructureSanityCheck(packageFile, rootElement); - dataTypes = rootElement.Element(Constants.Packaging.DataTypesNodeName); - languages = rootElement.Element(Constants.Packaging.LanguagesNodeName); - dictionaryItems = rootElement.Element(Constants.Packaging.DictionaryItemsNodeName); - macroes = rootElement.Element(Constants.Packaging.MacrosNodeName); - files = rootElement.Element(Constants.Packaging.FilesNodeName); - templates = rootElement.Element(Constants.Packaging.TemplatesNodeName); - documentTypes = rootElement.Element(Constants.Packaging.DocumentTypesNodeName); - styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName); - documentSet = rootElement.Element(Constants.Packaging.DocumentSetNodeName); - documents = rootElement.Element(Constants.Packaging.DocumentsNodeName); - actions = rootElement.Element(Constants.Packaging.ActionsNodeName); - - metaData = GetMetaData(rootElement); - installationSummary = new InstallationSummary {MetaData = metaData}; - } - catch (Exception e) - { - throw new Exception("Error reading " + packageFile, e); - } - - try - { - var dataTypeDefinitions = EmptyEnumerableIfNull(dataTypes) ?? InstallDataTypes(dataTypes, userId); - installationSummary.DataTypesInstalled = dataTypeDefinitions; - - var languagesInstalled = EmptyEnumerableIfNull(languages) ?? InstallLanguages(languages, userId); - installationSummary.LanguagesInstalled = languagesInstalled; - - var dictionaryInstalled = EmptyEnumerableIfNull(dictionaryItems) ?? InstallDictionaryItems(dictionaryItems); - installationSummary.DictionaryItemsInstalled = dictionaryInstalled; - - var macros = EmptyEnumerableIfNull(macroes) ?? InstallMacros(macroes, userId); - installationSummary.MacrosInstalled = macros; - - var keyValuePairs = EmptyEnumerableIfNull(packageFile) ?? InstallFiles(packageFile, files); - installationSummary.FilesInstalled = keyValuePairs; - - var templatesInstalled = EmptyEnumerableIfNull(templates) ?? InstallTemplats(templates, userId); - installationSummary.TemplatesInstalled = templatesInstalled; - - var documentTypesInstalled = EmptyEnumerableIfNull(documentTypes) ?? InstallDocumentTypes(documentTypes, userId); - installationSummary.ContentTypesInstalled =documentTypesInstalled; - - var stylesheetsInstalled = EmptyEnumerableIfNull(styleSheets) ?? InstallStylesheets(styleSheets); - installationSummary.StylesheetsInstalled = stylesheetsInstalled; - - var documentsInstalled = documents != null ? InstallDocuments(documents, userId) - : EmptyEnumerableIfNull(documentSet) - ?? InstallDocuments(documentSet, userId); - installationSummary.ContentInstalled = documentsInstalled; - - var packageActions = EmptyEnumerableIfNull(actions) ?? GetPackageActions(actions, metaData.Name); - installationSummary.Actions = packageActions; - - installationSummary.PackageInstalled = true; - - return installationSummary; - } - catch (Exception e) - { - throw new Exception("Error installing package " + packageFile, e); - } - } + private readonly PackageExtraction _packageExtraction; + private readonly PackageFileInstallation _packageFileInstallation; + private readonly CompiledPackageXmlParser _parser; + private readonly string _packagesFolderPath; + private readonly DirectoryInfo _packageExtractionFolder; + private readonly DirectoryInfo _applicationRootFolder; /// - /// Temperary check to test that we support stylesheets + /// Constructor /// - /// - private void PackageSupportedCheck(XElement rootElement) + /// + /// + /// + /// + /// The relative path of the package storage folder (i.e. ~/App_Data/Packages ) + /// + /// + /// The root folder of the application + /// + /// + /// The destination root folder to extract the package files (generally the same as applicationRoot) but can be modified for testing + /// + public PackageInstallation(IPackagingService packagingService, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, + string packagesFolderPath, DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) { - XElement styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName); - if (styleSheets != null && styleSheets.Elements().Any()) - throw new NotSupportedException("Stylesheets is not suported in this version of umbraco"); + _packageExtraction = new PackageExtraction(); + _packageFileInstallation = packageFileInstallation; + _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); + _parser = parser; + _packagesFolderPath = packagesFolderPath; + _applicationRootFolder = applicationRootFolder; + _packageExtractionFolder = packageExtractionFolder; } - private static T[] EmptyArrayIfNull(object obj) + public CompiledPackage ReadPackage(string packageFileName) { - return obj == null ? new T[0] : null; + if (packageFileName == null) throw new ArgumentNullException(nameof(packageFileName)); + var packageZipFile = GetPackageZipFile(packageFileName); + var doc = GetConfigXmlDoc(packageZipFile); + + var compiledPackage = _parser.ToCompiledPackage(doc, Path.GetFileName(packageZipFile.FullName), _applicationRootFolder.FullName); + + ValidatePackageFile(packageZipFile, compiledPackage); + + return compiledPackage; } + //fixme: Should we move all of the ImportXXXX methods here instead of on the IPackagingService? we don't want to have cicurlar refs + + public IEnumerable InstallPackageFiles(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId) + { + if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); + if (compiledPackage == null) throw new ArgumentNullException(nameof(compiledPackage)); + + //these should be the same, TODO: we should have a better validator for this + if (packageDefinition.Name != compiledPackage.Name) + throw new InvalidOperationException("The package definition does not match the compiled package manifest"); + + var packageZipFile = GetPackageZipFile(compiledPackage.PackageFileName); + + return _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _packageExtractionFolder.FullName); + } + + public InstallationSummary InstallPackageData(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId) + { + //fixme: fill this in + throw new NotImplementedException(); + } + + //public InstallationSummary InstallPackage(FileInfo packageFile, int userId) + //{ + // XElement dataTypes; + // XElement languages; + // XElement dictionaryItems; + // XElement macroes; + // XElement files; + // XElement templates; + // XElement documentTypes; + // XElement styleSheets; + // XElement documentSet; + // XElement documents; + // XElement actions; + // IPackageInfo metaData; + // InstallationSummary installationSummary; + + // try + // { + // XElement rootElement = GetConfigXmlElement(packageFile); + // PackageSupportedCheck(rootElement); + // PackageStructureSanityCheck(packageFile, rootElement); + // dataTypes = rootElement.Element(Constants.Packaging.DataTypesNodeName); + // languages = rootElement.Element(Constants.Packaging.LanguagesNodeName); + // dictionaryItems = rootElement.Element(Constants.Packaging.DictionaryItemsNodeName); + // macroes = rootElement.Element(Constants.Packaging.MacrosNodeName); + // files = rootElement.Element(Constants.Packaging.FilesNodeName); + // templates = rootElement.Element(Constants.Packaging.TemplatesNodeName); + // documentTypes = rootElement.Element(Constants.Packaging.DocumentTypesNodeName); + // styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName); + // documentSet = rootElement.Element(Constants.Packaging.DocumentSetNodeName); + // documents = rootElement.Element(Constants.Packaging.DocumentsNodeName); + // actions = rootElement.Element(Constants.Packaging.ActionsNodeName); + + // metaData = GetMetaData(rootElement); + // installationSummary = new InstallationSummary {MetaData = metaData}; + // } + // catch (Exception e) + // { + // throw new Exception("Error reading " + packageFile, e); + // } + + // try + // { + // var dataTypeDefinitions = EmptyEnumerableIfNull(dataTypes) ?? InstallDataTypes(dataTypes, userId); + // installationSummary.DataTypesInstalled = dataTypeDefinitions; + + // var languagesInstalled = EmptyEnumerableIfNull(languages) ?? InstallLanguages(languages, userId); + // installationSummary.LanguagesInstalled = languagesInstalled; + + // var dictionaryInstalled = EmptyEnumerableIfNull(dictionaryItems) ?? InstallDictionaryItems(dictionaryItems); + // installationSummary.DictionaryItemsInstalled = dictionaryInstalled; + + // var macros = EmptyEnumerableIfNull(macroes) ?? InstallMacros(macroes, userId); + // installationSummary.MacrosInstalled = macros; + + // var templatesInstalled = EmptyEnumerableIfNull(templates) ?? InstallTemplats(templates, userId); + // installationSummary.TemplatesInstalled = templatesInstalled; + + // var documentTypesInstalled = EmptyEnumerableIfNull(documentTypes) ?? InstallDocumentTypes(documentTypes, userId); + // installationSummary.ContentTypesInstalled =documentTypesInstalled; + + // var stylesheetsInstalled = EmptyEnumerableIfNull(styleSheets) ?? InstallStylesheets(styleSheets); + // installationSummary.StylesheetsInstalled = stylesheetsInstalled; + + // var documentsInstalled = documents != null ? InstallDocuments(documents, userId) + // : EmptyEnumerableIfNull(documentSet) + // ?? InstallDocuments(documentSet, userId); + // installationSummary.ContentInstalled = documentsInstalled; + + // var packageActions = EmptyEnumerableIfNull(actions) ?? GetPackageActions(actions, metaData.Name); + // installationSummary.Actions = packageActions; + + // installationSummary.PackageInstalled = true; + + // return installationSummary; + // } + // catch (Exception e) + // { + // throw new Exception("Error installing package " + packageFile, e); + // } + //} + + private FileInfo GetPackageZipFile(string packageFileName) => new FileInfo(IOHelper.MapPath(_packagesFolderPath).EnsureEndsWith('\\') + packageFileName); + private static IEnumerable EmptyEnumerableIfNull(object obj) { return obj == null ? Enumerable.Empty() : null; } - private XDocument GetConfigXmlDoc(string packageFilePath) + private XDocument GetConfigXmlDoc(FileInfo packageFile) { - var configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFilePath, - Constants.Packaging.PackageXmlFileName, out _); + var configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFile, Constants.Packaging.PackageXmlFileName, out _); - return XDocument.Parse(configXmlContent); - } + var document = XDocument.Parse(configXmlContent); - public XElement GetConfigXmlElement(string packageFilePath) - { - var document = GetConfigXmlDoc(packageFilePath); if (document.Root == null || document.Root.Name.LocalName.Equals(Constants.Packaging.UmbPackageNodeName) == false) - { - throw new ArgumentException("xml does not have a root node called \"umbPackage\"", packageFilePath); - } + throw new FormatException("xml does not have a root node called \"umbPackage\""); + + return document; + } + + public XElement GetConfigXmlElement(FileInfo packageFile) + { + var document = GetConfigXmlDoc(packageFile); return document.Root; } - private void PackageStructureSanityCheck(string packageFilePath, XElement rootElement) + private void ValidatePackageFile(FileInfo packageFile, CompiledPackage package) { - XElement filesElement = rootElement.Element(Constants.Packaging.FilesNodeName); - if (filesElement != null) + if (!(package.Files?.Count > 0)) return; + + var sourceDestination = _parser.ExtractSourceDestinationFileInformation(package.Files).ToArray(); + + var missingFiles = _packageExtraction.FindMissingFiles(packageFile, sourceDestination.Select(i => i.packageUniqueFile)).ToArray(); + + if (missingFiles.Any()) { - var sourceDestination = ExtractSourceDestinationFileInformation(filesElement).ToArray(); + throw new Exception("The following file(s) are missing in the package: " + + string.Join(", ", missingFiles.Select( + mf => + { + var sd = sourceDestination.Single(fi => fi.packageUniqueFile == mf); + return $"source: \"{sd.packageUniqueFile}\" destination: \"{sd.appRelativePath}\""; + }))); + } - var missingFiles = _packageExtraction.FindMissingFiles(packageFilePath, sourceDestination.Select(i => i.Key)).ToArray(); + IEnumerable duplicates = _packageExtraction.FindDuplicateFileNames(packageFile).ToArray(); - if (missingFiles.Any()) - { - throw new Exception("The following file(s) are missing in the package: " + - string.Join(", ", missingFiles.Select( - mf => - { - var sd = sourceDestination.Single(fi => fi.Key == mf); - return string.Format("source: \"{0}\" destination: \"{1}\"", - sd.Key, sd.Value); - }))); - } - - IEnumerable dubletFileNames = _packageExtraction.FindDubletFileNames(packageFilePath).ToArray(); - - if (dubletFileNames.Any()) - { - throw new Exception("The following filename(s) are found more than one time in the package, since the filename is used ad primary key, this is not allowed: " + - string.Join(", ", dubletFileNames)); - } + if (duplicates.Any()) + { + throw new Exception("The following filename(s) are found more than one time in the package, since the filename is used ad primary key, this is not allowed: " + + string.Join(", ", duplicates)); } } @@ -346,7 +305,7 @@ namespace Umbraco.Core.Packaging return _packagingService.ImportContentTypes(documentTypes, userId); } - private IEnumerable InstallTemplats(XElement templateElement, int userId = 0) + private IEnumerable InstallTemplates(XElement templateElement, int userId = 0) { if (string.Equals(Constants.Packaging.TemplatesNodeName, templateElement.Name.LocalName) == false) { @@ -356,23 +315,6 @@ namespace Umbraco.Core.Packaging return _packagingService.ImportTemplates(templateElement, userId); } - private IEnumerable InstallFiles(string packageFilePath, XElement filesElement) - { - var sourceDestination = ExtractSourceDestinationFileInformation(filesElement); - sourceDestination = AppendRootToDestination(FullPathToRoot, sourceDestination); - - _packageExtraction.CopyFilesFromArchive(packageFilePath, sourceDestination); - - return sourceDestination.Select(sd => sd.Value).ToArray(); - } - - private KeyValuePair[] AppendRootToDestination(string fullpathToRoot, IEnumerable> sourceDestination) - { - return - sourceDestination.Select( - sd => new KeyValuePair(sd.Key, Path.Combine(fullpathToRoot, sd.Value))).ToArray(); - } - private IEnumerable InstallMacros(XElement macroElements, int userId = 0) { if (string.Equals(Constants.Packaging.MacrosNodeName, macroElements.Name.LocalName) == false) @@ -414,164 +356,6 @@ namespace Umbraco.Core.Packaging } return _packagingService.ImportDataTypeDefinitions(dataTypeElements, userId); } - - private PreInstallWarnings GetPreInstallWarnings(XElement rootElement) - { - XElement files = rootElement.Element(Constants.Packaging.FilesNodeName); - XElement styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName); - XElement templates = rootElement.Element(Constants.Packaging.TemplatesNodeName); - XElement alias = rootElement.Element(Constants.Packaging.MacrosNodeName); - - var sourceDestination = EmptyArrayIfNull>(files) ?? ExtractSourceDestinationFileInformation(files); - - var installWarnings = new PreInstallWarnings(); - - var macroAliases = EmptyEnumerableIfNull(alias) ?? ConflictingPackageData.FindConflictingMacros(alias); - installWarnings.ConflictingMacroAliases = macroAliases; - - var templateAliases = EmptyEnumerableIfNull(templates) ?? ConflictingPackageData.FindConflictingTemplates(templates); - installWarnings.ConflictingTemplateAliases = templateAliases; - - var stylesheetNames = EmptyEnumerableIfNull(styleSheets) ?? ConflictingPackageData.FindConflictingStylesheets(styleSheets); - installWarnings.ConflictingStylesheetNames = stylesheetNames; - - installWarnings.UnsecureFiles = FindUnsecureFiles(sourceDestination); - installWarnings.FilesReplaced = FindFilesToBeReplaced(sourceDestination); - - return installWarnings; - } - - private KeyValuePair[] FindFilesToBeReplaced(IEnumerable> sourceDestination) - { - return sourceDestination.Where(sd => File.Exists(Path.Combine(FullPathToRoot, sd.Value))).ToArray(); - } - - private KeyValuePair[] FindUnsecureFiles(IEnumerable> sourceDestinationPair) - { - return sourceDestinationPair.Where(sd => IsFileDestinationUnsecure(sd.Value)).ToArray(); - } - - private bool IsFileDestinationUnsecure(string destination) - { - var unsecureDirNames = new[] {"bin", "app_code"}; - if(unsecureDirNames.Any(ud => destination.StartsWith(ud, StringComparison.InvariantCultureIgnoreCase))) - return true; - - string extension = Path.GetExtension(destination); - return extension != null && extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase); - } - - private KeyValuePair[] ExtractSourceDestinationFileInformation(XElement filesElement) - { - if (string.Equals(Constants.Packaging.FilesNodeName, filesElement.Name.LocalName) == false) - { - throw new ArgumentException("the root element must be \"Files\"", "filesElement"); - } - - return filesElement.Elements(Constants.Packaging.FileNodeName) - .Select(e => - { - XElement guidElement = e.Element(Constants.Packaging.GuidNodeName); - if (guidElement == null) - { - throw new ArgumentException("Missing element \"" + Constants.Packaging.GuidNodeName + "\"", - "filesElement"); - } - - XElement orgPathElement = e.Element(Constants.Packaging.OrgPathNodeName); - if (orgPathElement == null) - { - throw new ArgumentException("Missing element \"" + Constants.Packaging.OrgPathNodeName + "\"", - "filesElement"); - } - - XElement orgNameElement = e.Element(Constants.Packaging.OrgNameNodeName); - if (orgNameElement == null) - { - throw new ArgumentException("Missing element \"" + Constants.Packaging.OrgNameNodeName + "\"", - "filesElement"); - } - - var fileName = PrepareAsFilePathElement(orgNameElement.Value); - var relativeDir = UpdatePathPlaceholders(PrepareAsFilePathElement(orgPathElement.Value)); - - var relativePath = Path.Combine(relativeDir, fileName); - - - return new KeyValuePair(guidElement.Value, relativePath); - }).ToArray(); - } - - private static string PrepareAsFilePathElement(string pathElement) - { - return pathElement.TrimStart(new[] {'\\', '/', '~'}).Replace("/", "\\"); - } - - private IPackageInfo GetMetaData(XElement xRootElement) - { - XElement infoElement = xRootElement.Element(Constants.Packaging.InfoNodeName); - - if (infoElement == null) - { - throw new ArgumentException("Did not hold a \"" + Constants.Packaging.InfoNodeName + "\" element", - "xRootElement"); - } - - var majorElement = infoElement.XPathSelectElement(Constants.Packaging.PackageRequirementsMajorXpath); - var minorElement = infoElement.XPathSelectElement(Constants.Packaging.PackageRequirementsMinorXpath); - var patchElement = infoElement.XPathSelectElement(Constants.Packaging.PackageRequirementsPatchXpath); - var nameElement = infoElement.XPathSelectElement(Constants.Packaging.PackageNameXpath); - var versionElement = infoElement.XPathSelectElement(Constants.Packaging.PackageVersionXpath); - var urlElement = infoElement.XPathSelectElement(Constants.Packaging.PackageUrlXpath); - var licenseElement = infoElement.XPathSelectElement(Constants.Packaging.PackageLicenseXpath); - var authorNameElement = infoElement.XPathSelectElement(Constants.Packaging.AuthorNameXpath); - var authorUrlElement = infoElement.XPathSelectElement(Constants.Packaging.AuthorWebsiteXpath); - var readmeElement = infoElement.XPathSelectElement(Constants.Packaging.ReadmeXpath); - - XElement controlElement = xRootElement.Element(Constants.Packaging.ControlNodeName); - - return new PackageDefinition - { - Name = StringValue(nameElement), - Version = StringValue(versionElement), - Url = StringValue(urlElement), - License = StringValue(licenseElement), - LicenseUrl = StringAttribute(licenseElement, Constants.Packaging.PackageLicenseXpathUrlAttribute), - Author = StringValue(authorNameElement), - AuthorUrl = StringValue(authorUrlElement), - Readme = StringValue(readmeElement), - Control = StringValue(controlElement), - UmbracoVersion = new Version(IntValue(majorElement), IntValue(minorElement), IntValue(patchElement)) - }; - } - - private static string StringValue(XElement xElement, string defaultValue = "") - { - return xElement == null ? defaultValue : xElement.Value; - } - - private static string StringAttribute(XElement xElement, string attribute, string defaultValue = "") - { - return xElement == null - ? defaultValue - : xElement.HasAttributes ? xElement.AttributeValue(attribute) : defaultValue; - } - - private static int IntValue(XElement xElement, int defaultValue = 0) - { - return xElement == null ? defaultValue : int.TryParse(xElement.Value, out var val) ? val : defaultValue; - } - - private static string UpdatePathPlaceholders(string path) - { - if (path.Contains("[$")) - { - //this is experimental and undocumented... - path = path.Replace("[$UMBRACO]", SystemDirectories.Umbraco); - path = path.Replace("[$CONFIG]", SystemDirectories.Config); - path = path.Replace("[$DATA]", SystemDirectories.Data); - } - return path; - } + } } diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 5b432d3339..fcb0c66401 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; using System.Xml.Linq; using Umbraco.Core.Models; @@ -10,6 +11,33 @@ namespace Umbraco.Core.Services { public interface IPackagingService : IService { + #region Package Installation + + /// + /// Returns a result from an umbraco package file (zip) + /// + /// + /// + CompiledPackage GetCompiledPackageInfo(string packageFileName); + + /// + /// Installs the package files contained in an umbraco package file (zip) + /// + /// + /// + /// + IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0); + + /// + /// Installs the data, entities, objects contained in an umbraco package file (zip) + /// + /// + /// + /// + InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0); + + #endregion + #region Installed Packages IEnumerable GetAllInstalledPackages(); @@ -116,16 +144,18 @@ namespace Umbraco.Core.Services /// Optional id of the User performing the operation. Default is zero (admin) /// Optional parameter indicating whether or not to raise events /// An enumrable list of generated Templates - IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true); + IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true); #endregion /// - /// This will fetch an Umbraco package file from the package repository and return the relative file path to the downloaded package file + /// This will fetch an Umbraco package file from the package repository and return the file name of the downloaded package /// /// /// /// The current user id performing the operation - /// + /// + /// The file name of the downloaded package which will exist in ~/App_Data/packages + /// Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId); } } diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index e7b33dd86d..7c379dc2dc 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -32,7 +32,7 @@ namespace Umbraco.Core.Services.Implement public class PackagingService : IPackagingService { //fixme: inject when ready to use this - private IPackageInstallation _packageInstallation; + private readonly IPackageInstallation _packageInstallation; private readonly ILogger _logger; private readonly IContentService _contentService; @@ -961,9 +961,6 @@ namespace Umbraco.Core.Services.Implement #endregion - #region Files - #endregion - #region Languages @@ -1160,7 +1157,7 @@ namespace Umbraco.Core.Services.Implement using (var fs1 = new FileStream(packageFilePath, FileMode.Create)) { fs1.Write(bytes, 0, bytes.Length); - return "packages\\" + packageId + ".umb"; + return packageId + ".umb"; } } @@ -1305,37 +1302,46 @@ namespace Umbraco.Core.Services.Implement #region Installation - //fixme: None of these methods are actually used! They have unit tests for them though, but we don't actively use this yet but we should! + public CompiledPackage GetCompiledPackageInfo(string packageFileName) => _packageInstallation.ReadPackage(packageFileName); - internal IPackageInstallation PackageInstallation + public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0) { - private get { return _packageInstallation ?? new PackageInstallation(this, _macroService, _fileService, new PackageExtraction()); } - set { _packageInstallation = value; } + if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); + if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); + if (packageDefinition.Name == default) throw new ArgumentException("The package definition has incomplete information"); + + var compiledPackage = GetCompiledPackageInfo(packageFileName); + if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName); + + var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId); + + SaveInstalledPackage(packageDefinition); + + if (userId > -1) + _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package files installed for package '{compiledPackage.Name}'."); + + return files; } - internal InstallationSummary InstallPackage(string packageFilePath, int userId = 0, bool raiseEvents = false) + public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0) { - var metaData = GetPackageMetaData(packageFilePath); + if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); + if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); + if (packageDefinition.Name == default) throw new ArgumentException("The package definition has incomplete information"); - if (raiseEvents && ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFilePath, metaData), this)) - return new InstallationSummary { MetaData = metaData }; + var compiledPackage = GetCompiledPackageInfo(packageFileName); + if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName); - var installationSummary = PackageInstallation.InstallPackage(packageFilePath, userId); + if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFileName, compiledPackage), this)) + return new InstallationSummary { MetaData = compiledPackage }; - if (raiseEvents) - ImportedPackage.RaiseEvent(new ImportPackageEventArgs(installationSummary, metaData, false), this); + var summary = _packageInstallation.InstallPackageData(packageDefinition, compiledPackage, userId); - return installationSummary; - } + _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package data installed for package '{compiledPackage.Name}'."); - internal PreInstallWarnings GetPackageWarnings(string packageFilePath) - { - return PackageInstallation.GetPreInstallWarnings(packageFilePath); - } + ImportedPackage.RaiseEvent(new ImportPackageEventArgs(summary, compiledPackage, false), this); - internal IPackageInfo GetPackageMetaData(string packageFilePath) - { - return PackageInstallation.GetMetaData(packageFilePath); + return summary; } #endregion diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 038d531bd4..2ee5d13f6d 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -444,11 +444,14 @@ + + + @@ -889,9 +892,6 @@ - - - diff --git a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs index 40500d6bcb..e059d87524 100644 --- a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs @@ -87,10 +87,10 @@ namespace Umbraco.Tests.Packaging var def2 = new PackageDefinition { - Name = "test", - Url = "http://test.com", - Author = "Someone", - AuthorUrl = "http://test.com" + Name = "test2", + Url = "http://test2.com", + Author = "Someone2", + AuthorUrl = "http://test2.com" }; result = PackageBuilder.SavePackage(def2); diff --git a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs b/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs index 5416162ed2..61494166ff 100644 --- a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs +++ b/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs @@ -12,11 +12,11 @@ namespace Umbraco.Tests.Packaging { private const string PackageFileName = "Document_Type_Picker_1.1.umb"; - private static string GetTestPackagePath(string packageName) + private static FileInfo GetTestPackagePath(string packageName) { const string testPackagesDirName = "Packaging\\Packages"; string path = Path.Combine(IOHelper.GetRootDirectorySafe(), testPackagesDirName, packageName); - return path; + return new FileInfo(path); } [Test] diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 0855d81548..fe7a5fbe5c 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -1,74 +1,113 @@ -using Moq; +using System; +using System.IO; +using System.Linq; +using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; namespace Umbraco.Tests.Packaging { [TestFixture] - public class PackageInstallationTest + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] + public class PackageInstallationTest : TestWithDatabaseBase { - private const string Xml = @" - - - 095e064b-ba4d-442d-9006-3050983c13d8.dll/binAuros.DocumentTypePicker.dll - - - Document Type Picker - 1.1 - MIT - http://www.auros.co.uk - - 3 - 0 - 0 - - - - @tentonipete - auros.co.uk - - - - - - - - - - - - - - -"; + private Guid _testBaseFolder; + + public override void SetUp() + { + base.SetUp(); + _testBaseFolder = Guid.NewGuid(); + } + + public override void TearDown() + { + base.TearDown(); + + //clear out files/folders + var path = IOHelper.MapPath("~/" + _testBaseFolder); + if (Directory.Exists(path)) + Directory.Delete(path, true); + } + + private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser(new ConflictingPackageData(ServiceContext.MacroService, ServiceContext.FileService)); + + private IPackageInstallation PackageInstallation => new PackageInstallation( + ServiceContext.PackagingService, + new PackageFileInstallation(Parser, ProfilingLogger), + Parser, + packagesFolderPath: "~/Packaging/packages",//this is where our test zip file is + applicationRootFolder: new DirectoryInfo(IOHelper.GetRootDirectorySafe()), + packageExtractionFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder + + const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; + + //[Test] + //public void PackagingService_Can_ImportPackage() + //{ + // const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; + + // string testPackagePath = GetTestPackagePath(documentTypePickerUmb); + + // InstallationSummary installationSummary = packagingService.InstallPackage(testPackagePath); + + // Assert.IsNotNull(installationSummary); + //} + [Test] - public void Test() + public void Can_Read_Compiled_Package() { - // Arrange - const string pagePath = "Test.umb"; + var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + Assert.IsNotNull(package); + Assert.AreEqual(1, package.Files.Count); + Assert.AreEqual("095e064b-ba4d-442d-9006-3050983c13d8.dll", package.Files[0].UniqueFileName); + Assert.AreEqual("/bin", package.Files[0].OriginalPath); + Assert.AreEqual("Auros.DocumentTypePicker.dll", package.Files[0].OriginalName); + Assert.AreEqual("Document Type Picker", package.Name); + Assert.AreEqual("1.1", package.Version); + Assert.AreEqual("http://www.opensource.org/licenses/mit-license.php", package.LicenseUrl); + Assert.AreEqual("MIT", package.License); + Assert.AreEqual(3, package.UmbracoVersion.Major); + Assert.AreEqual(RequirementsType.Legacy, package.UmbracoVersionRequirementsType); + Assert.AreEqual("@tentonipete", package.Author); + Assert.AreEqual("auros.co.uk", package.AuthorUrl); + Assert.AreEqual("Document Type Picker datatype that enables back office user to select one or many document types.", package.Readme); - var packageExtraction = new Mock(); - - string test; - packageExtraction.Setup(a => a.ReadTextFileFromArchive(pagePath, Constants.Packaging.PackageXmlFileName, out test)).Returns(Xml); - - var fileService = new Mock(); - var macroService = new Mock(); - var packagingService = new Mock(); - - var sut = new PackageInstallation(packagingService.Object, macroService.Object, fileService.Object, packageExtraction.Object); - - // Act - InstallationSummary installationSummary = sut.InstallPackage(pagePath, -1); - - // Assert - Assert.IsNotNull(installationSummary); - //Assert.Inconclusive("Lots of more tests can be written"); } + [Test] + public void Can_Read_Compiled_Package_Warnings() + { + + + var preInstallWarnings = PackageInstallation.ReadPackage(documentTypePickerUmb).Warnings; + Assert.IsNotNull(preInstallWarnings); + + //TODO: Assert! + } + + [Test] + public void Install_Files() + { + var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var def = PackageDefinition.FromCompiledPackage(package); + def.Id = 1; + def.PackageId = Guid.NewGuid(); + + var result = PackageInstallation.InstallPackageFiles(def, package, -1).ToList(); + + Assert.AreEqual(1, result.Count); + Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", result[0]); + Assert.IsTrue(File.Exists(Path.Combine(IOHelper.MapPath("~/" + _testBaseFolder), result[0]))); + } + + } } diff --git a/src/Umbraco.Tests/Services/PackagingServiceTests.cs b/src/Umbraco.Tests/Services/PackagingServiceTests.cs index 0f57298c88..f6878e9407 100644 --- a/src/Umbraco.Tests/Services/PackagingServiceTests.cs +++ b/src/Umbraco.Tests/Services/PackagingServiceTests.cs @@ -14,54 +14,7 @@ namespace Umbraco.Tests.Services { - private static string GetTestPackagePath(string packageName) - { - const string testPackagesDirName = "Packaging\\Packages"; - string path = Path.Combine(IOHelper.GetRootDirectorySafe(), testPackagesDirName, packageName); - return path; - } - - - [Test] - public void PackagingService_Can_ImportPackage() - { - var packagingService = (PackagingService)ServiceContext.PackagingService; - - const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; - - string testPackagePath = GetTestPackagePath(documentTypePickerUmb); - - InstallationSummary installationSummary = packagingService.InstallPackage(testPackagePath); - - Assert.IsNotNull(installationSummary); - } - - - [Test] - public void PackagingService_Can_GetPackageMetaData() - { - var packagingService = (PackagingService)ServiceContext.PackagingService; - - const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; - - string testPackagePath = GetTestPackagePath(documentTypePickerUmb); - - var packageMetaData = packagingService.GetPackageMetaData(testPackagePath); - Assert.IsNotNull(packageMetaData); - } - - [Test] - public void PackagingService_Can_GetPackageWarnings() - { - var packagingService = (PackagingService)ServiceContext.PackagingService; - - const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; - - string testPackagePath = GetTestPackagePath(documentTypePickerUmb); - - PreInstallWarnings preInstallWarnings = packagingService.GetPackageWarnings(testPackagePath); - Assert.IsNotNull(preInstallWarnings); - } + } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html index 7f22b7ace8..5e3ef6ad1c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html @@ -128,7 +128,7 @@
Read me
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index fc272c86ff..93c2ce05ed 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -325,7 +325,7 @@
Read me
- +
diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 3e7c14147b..daf152c29b 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -161,7 +161,7 @@ namespace Umbraco.Web.Composing #region Web Actions - public static void RestartAppPool() + internal static void RestartAppPool() { // see notes in overload @@ -175,7 +175,7 @@ namespace Umbraco.Web.Composing HttpRuntime.UnloadAppDomain(); } - public static void RestartAppPool(HttpContextBase httpContext) + internal static void RestartAppPool(HttpContextBase httpContext) { // we're going to put an application wide flag to show that the application is about to restart. // we're doing this because if there is a script checking if the app pool is fully restarted, then diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 73d50eb48a..24cc999c6b 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -29,7 +29,6 @@ using Umbraco.Web.UI; using Umbraco.Web.UI.JavaScript; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; -using Umbraco.Web._Legacy.Packager; using File = System.IO.File; using Notification = Umbraco.Web.Models.ContentEditing.Notification; using Version = System.Version; @@ -302,37 +301,31 @@ namespace Umbraco.Web.Editors private void PopulateFromPackageData(LocalPackageInstallModel model) { - var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); - //this will load in all the metadata too - var tempDir = ins.Import(model.ZipFilePath, false); + var ins = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); - model.TemporaryDirectoryPath = Path.Combine(SystemDirectories.Data, tempDir); model.Name = ins.Name; model.Author = ins.Author; model.AuthorUrl = ins.AuthorUrl; model.IconUrl = ins.IconUrl; model.License = ins.License; model.LicenseUrl = ins.LicenseUrl; - model.ReadMe = ins.ReadMe; - model.ConflictingMacroAliases = ins.ConflictingMacroAliases; - model.ConflictingStyleSheetNames = ins.ConflictingStyleSheetNames; - model.ConflictingTemplateAliases = ins.ConflictingTemplateAliases; - model.ContainsMacroConflict = ins.ContainsMacroConflict; - model.ContainsStyleSheetConflicts = ins.ContainsStyleSheeConflicts; - model.ContainsTemplateConflicts = ins.ContainsTemplateConflicts; - model.ContainsUnsecureFiles = ins.ContainsUnsecureFiles; + model.Readme = ins.Readme; + model.ConflictingMacroAliases = ins.Warnings.ConflictingMacros.ToDictionary(x => x.Name, x => x.Alias); + model.ConflictingStyleSheetNames = ins.Warnings.ConflictingStylesheets.ToDictionary(x => x.Name, x => x.Alias); ; + model.ConflictingTemplateAliases = ins.Warnings.ConflictingTemplates.ToDictionary(x => x.Name, x => x.Alias); ; + model.ContainsUnsecureFiles = ins.Warnings.UnsecureFiles.Any(); model.Url = ins.Url; model.Version = ins.Version; - model.UmbracoVersion = ins.RequirementsType == RequirementsType.Strict - ? string.Format("{0}.{1}.{2}", ins.RequirementsMajor, ins.RequirementsMinor, ins.RequirementsPatch) + model.UmbracoVersion = ins.UmbracoVersionRequirementsType == RequirementsType.Strict + ? ins.UmbracoVersion.ToString(3) : string.Empty; //now we need to check for version comparison model.IsCompatible = true; - if (ins.RequirementsType == RequirementsType.Strict) + if (ins.UmbracoVersionRequirementsType == RequirementsType.Strict) { - var packageMinVersion = new System.Version(ins.RequirementsMajor, ins.RequirementsMinor, ins.RequirementsPatch); + var packageMinVersion = ins.UmbracoVersion; if (UmbracoVersion.Current < packageMinVersion) { model.IsCompatible = false; @@ -489,13 +482,12 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel Import(PackageInstallModel model) { - var ins = new Installer(Security.CurrentUser.Id); + var packageInfo = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); - var tempPath = ins.Import(model.ZipFilePath); //now we need to check for version comparison - if (ins.RequirementsType == RequirementsType.Strict) + if (packageInfo.UmbracoVersionRequirementsType == RequirementsType.Strict) { - var packageMinVersion = new System.Version(ins.RequirementsMajor, ins.RequirementsMinor, ins.RequirementsPatch); + var packageMinVersion = packageInfo.UmbracoVersion; if (UmbracoVersion.Current < packageMinVersion) { throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse( @@ -503,8 +495,13 @@ namespace Umbraco.Web.Editors } } - model.TemporaryDirectoryPath = Path.Combine(SystemDirectories.Data, tempPath); - model.Id = ins.CreateManifest(model.PackageGuid); + var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); + + //save to the installedPackages.config + packageDefinition.PackageId = model.PackageGuid; //fixme: why are we doing this? + Services.PackagingService.SaveInstalledPackage(packageDefinition); + + model.Id = packageDefinition.Id; return model; } @@ -517,9 +514,10 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel InstallFiles(PackageInstallModel model) { - var ins = new Installer(Security.CurrentUser.Id); - ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); - ins.InstallFiles(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); + var definition = Services.PackagingService.GetInstalledPackageById(model.Id); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); + + Services.PackagingService.InstallCompiledPackageFiles(definition, model.ZipFilePath, Security.GetUserId().ResultOr(0)); //set a restarting marker and reset the app pool Current.RestartAppPool(Request.TryGetHttpContext().Result); @@ -551,9 +549,10 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel InstallData(PackageInstallModel model) { - var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); - ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); - ins.InstallBusinessLogic(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); + var definition = Services.PackagingService.GetInstalledPackageById(model.Id); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); + + Services.PackagingService.InstallCompiledPackageData(definition, model.ZipFilePath, Security.GetUserId().ResultOr(0)); return model; } @@ -565,23 +564,21 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallResult CleanUp(PackageInstallModel model) { - var ins = new global::Umbraco.Web._Legacy.Packager.Installer(Security.CurrentUser.Id); - var tempDir = IOHelper.MapPath(model.TemporaryDirectoryPath); - ins.LoadConfig(IOHelper.MapPath(model.TemporaryDirectoryPath)); - ins.InstallCleanUp(model.Id, IOHelper.MapPath(model.TemporaryDirectoryPath)); + var packageInfo = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); var clientDependencyConfig = new ClientDependencyConfiguration(Logger); var clientDependencyUpdated = clientDependencyConfig.UpdateVersionNumber( UmbracoVersion.SemanticVersion, DateTime.UtcNow, "yyyyMMdd"); + //fixme: when do we delete the zip file? var redirectUrl = ""; - if (ins.Control.IsNullOrWhiteSpace() == false) + if (packageInfo.Control.IsNullOrWhiteSpace() == false) { //fixme: this needs to be replaced with an angular view the installer.aspx no longer exists. - redirectUrl = string.Format("/developer/framed/{0}", - Uri.EscapeDataString( - string.Format("/umbraco/developer/Packages/installer.aspx?installing=custominstaller&dir={0}&pId={1}&customControl={2}&customUrl={3}", tempDir, model.Id, ins.Control, ins.Url))); + //redirectUrl = string.Format("/developer/framed/{0}", + // Uri.EscapeDataString( + // string.Format("/umbraco/developer/Packages/installer.aspx?installing=custominstaller&dir={0}&pId={1}&customControl={2}&customUrl={3}", tempDir, model.Id, ins.Control, ins.Url))); } return new PackageInstallResult @@ -590,7 +587,6 @@ namespace Umbraco.Web.Editors ZipFilePath = model.ZipFilePath, PackageGuid = model.PackageGuid, RepositoryGuid = model.RepositoryGuid, - TemporaryDirectoryPath = model.TemporaryDirectoryPath, PostInstallationPath = redirectUrl }; diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs index ac859ee3aa..dd9b0a42d0 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs @@ -11,6 +11,7 @@ using umbraco; using Umbraco.Core; using Umbraco.Web.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; @@ -28,17 +29,18 @@ namespace Umbraco.Web.Install.Controllers [HttpInstallAuthorize] [AngularJsonOnlyConfiguration] [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] + //fixme: Is this used anymore?? public class InstallPackageController : ApiController { private readonly IPackagingService _packagingService; + private readonly UmbracoContext _umbracoContext; - public InstallPackageController(IPackagingService packagingService) + public InstallPackageController(IPackagingService packagingService, UmbracoContext umbracoContext) { _packagingService = packagingService; + _umbracoContext = umbracoContext; } - private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66"; - /// /// Empty action, useful for retrieving the base url for this controller /// @@ -50,7 +52,7 @@ namespace Umbraco.Web.Install.Controllers } /// - /// Connects to the repo, downloads the package and creates the manifest + /// Connects to the repo, downloads the package and creates the definition /// /// /// @@ -62,16 +64,19 @@ namespace Umbraco.Web.Install.Controllers UmbracoVersion.Current, UmbracoContext.Current.Security.CurrentUser.Id); - var installer = new _Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); + + var packageInfo = _packagingService.GetCompiledPackageInfo(packageFile); + if (packageInfo == null) throw new InvalidOperationException("Could not read package file " + packageFile); + + //save to the installedPackages.config + var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); + _packagingService.SaveInstalledPackage(packageDefinition); - var tempFile = installer.Import(packageFile); - installer.LoadConfig(tempFile); - var pId = installer.CreateManifest(model.KitGuid); return Json(new { success = true, - manifestId = pId, - packageFile = tempFile, + packageId = packageDefinition.Id, + packageFile = packageInfo.PackageFileName, percentage = 10, message = "Downloading starter kit files..." }, HttpStatusCode.OK); @@ -85,13 +90,16 @@ namespace Umbraco.Web.Install.Controllers public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) { model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); - installer.LoadConfig(model.PackageFile); - installer.InstallFiles(model.ManifestId, model.PackageFile); + + var definition = _packagingService.GetInstalledPackageById(model.PackageId); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); + + _packagingService.InstallCompiledPackageFiles(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); + return Json(new { success = true, - model.ManifestId, + ManifestId = model.PackageId, model.PackageFile, percentage = 20, message = "Installing starter kit files" @@ -141,13 +149,16 @@ namespace Umbraco.Web.Install.Controllers public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) { model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); - installer.LoadConfig(model.PackageFile); - installer.InstallBusinessLogic(model.ManifestId, model.PackageFile); + + var definition = _packagingService.GetInstalledPackageById(model.PackageId); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); + + _packagingService.InstallCompiledPackageData(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); + return Json(new { success = true, - model.ManifestId, + ManifestId = model.PackageId, model.PackageFile, percentage = 70, message = "Installing starter kit files" @@ -162,18 +173,11 @@ namespace Umbraco.Web.Install.Controllers public HttpResponseMessage CleanupInstallation(InstallPackageModel model) { model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var installer = new global::Umbraco.Web._Legacy.Packager.Installer(UmbracoContext.Current.Security.CurrentUser.Id); - installer.LoadConfig(model.PackageFile); - installer.InstallCleanUp(model.ManifestId, model.PackageFile); - - // library.RefreshContent is obsolete, would need to RefreshAll... snapshot, - // but it should be managed automatically by services and caches! - //DistributedCache.Instance.RefreshAll...(); - + return Json(new { success = true, - model.ManifestId, + ManifestId = model.PackageId, model.PackageFile, percentage = 100, message = "Starter kit has been installed" diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs index 075a61ca95..8c168f7230 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Threading.Tasks; using System.Web; using Umbraco.Web.Install.Models; -using Umbraco.Web._Legacy.Packager; namespace Umbraco.Web.Install.InstallSteps { @@ -15,31 +14,26 @@ namespace Umbraco.Web.Install.InstallSteps { var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "StarterKitDownload"); - var manifestId = Convert.ToInt32(previousStep.AdditionalData["manifestId"]); + var packageId = Convert.ToInt32(previousStep.AdditionalData["packageId"]); var packageFile = (string)previousStep.AdditionalData["packageFile"]; - CleanupInstallation(manifestId, packageFile); + CleanupInstallation(packageId, packageFile); return Task.FromResult(null); } - private void CleanupInstallation(int manifestId, string packageFile) + private void CleanupInstallation(int packageId, string packageFile) { packageFile = HttpUtility.UrlDecode(packageFile); - var installer = new Installer(); - installer.LoadConfig(packageFile); - installer.InstallCleanUp(manifestId, packageFile); - // library.RefreshContent is obsolete, would need to RefreshAll... snapshot, - // but it should be managed automatically by services and caches! - //DistributedCache.Instance.RefreshAll...(); + //fixme: When does the zip file get deleted? } public override bool RequiresExecution(object model) { var installSteps = InstallStatusTracker.GetStatus().ToArray(); //this step relies on the preious one completed - because it has stored some information we need - if (installSteps.Any(x => x.Name == "StarterKitDownload" && x.AdditionalData.ContainsKey("manifestId")) == false) + if (installSteps.Any(x => x.Name == "StarterKitDownload" && x.AdditionalData.ContainsKey("packageId")) == false) { return false; } diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 66d1b0a20c..0fe1e333d3 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -5,9 +5,9 @@ using System.Threading.Tasks; using System.Web; using Umbraco.Core.Services; using Umbraco.Core.Configuration; +using Umbraco.Core.Models.Packaging; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; -using Umbraco.Web._Legacy.Packager; namespace Umbraco.Web.Install.InstallSteps { @@ -29,7 +29,7 @@ namespace Umbraco.Web.Install.InstallSteps _packageService = packageService; } - private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66"; + //private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66"; public override async Task ExecuteAsync(Guid? starterKitId) { @@ -55,34 +55,33 @@ namespace Umbraco.Web.Install.InstallSteps return new InstallSetupResult(new Dictionary { - {"manifestId", result.Item2}, + {"packageId", result.Item2}, {"packageFile", result.Item1} }); } private async Task> DownloadPackageFilesAsync(Guid kitGuid) { - var installer = new Installer(); - //Go get the package file from the package repo - var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); + var packageFileName = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); + if (packageFileName == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); - var tempFile = installer.Import(packageFile); - installer.LoadConfig(tempFile); - var pId = installer.CreateManifest(kitGuid); + //add an entry to the installedPackages.config + var compiledPackage = _packageService.GetCompiledPackageInfo(packageFileName); + var packageDefinition = PackageDefinition.FromCompiledPackage(compiledPackage); + _packageService.SaveInstalledPackage(packageDefinition); - InstallPackageFiles(pId, tempFile); + InstallPackageFiles(packageDefinition, compiledPackage.PackageFileName); - return new Tuple(tempFile, pId); + return new Tuple(compiledPackage.PackageFileName, packageDefinition.Id); } - private void InstallPackageFiles(int manifestId, string packageFile) + private void InstallPackageFiles(PackageDefinition packageDefinition, string packageFileName) { - packageFile = HttpUtility.UrlDecode(packageFile); - var installer = new Installer(); - installer.LoadConfig(packageFile); - installer.InstallFiles(manifestId, packageFile); + if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); + packageFileName = HttpUtility.UrlDecode(packageFileName); + _packageService.InstallCompiledPackageData(packageDefinition, packageFileName, _umbracoContext.Security.GetUserId().ResultOr(0)); } public override string View => _packageService.GetAllInstalledPackages().Any() ? string.Empty : base.View; diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 0e189c5a6d..9d3f38b061 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -2,9 +2,9 @@ using System.Linq; using System.Threading.Tasks; using System.Web; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; -using Umbraco.Web._Legacy.Packager; namespace Umbraco.Web.Install.InstallSteps { @@ -14,10 +14,14 @@ namespace Umbraco.Web.Install.InstallSteps internal class StarterKitInstallStep : InstallSetupStep { private readonly HttpContextBase _httContext; + private readonly UmbracoContext _umbracoContext; + private readonly IPackagingService _packagingService; - public StarterKitInstallStep(HttpContextBase httContext) + public StarterKitInstallStep(HttpContextBase httContext, UmbracoContext umbracoContext, IPackagingService packagingService) { _httContext = httContext; + _umbracoContext = umbracoContext; + _packagingService = packagingService; } @@ -25,29 +29,31 @@ namespace Umbraco.Web.Install.InstallSteps { var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "StarterKitDownload"); - var manifestId = Convert.ToInt32(previousStep.AdditionalData["manifestId"]); + var packageId = Convert.ToInt32(previousStep.AdditionalData["packageId"]); var packageFile = (string)previousStep.AdditionalData["packageFile"]; - InstallBusinessLogic(manifestId, packageFile); + InstallBusinessLogic(packageId, packageFile); Current.RestartAppPool(_httContext); return Task.FromResult(null); } - private void InstallBusinessLogic(int manifestId, string packageFile) + private void InstallBusinessLogic(int packageId, string packageFile) { packageFile = HttpUtility.UrlDecode(packageFile); - var installer = new Installer(); - installer.LoadConfig(packageFile); - installer.InstallBusinessLogic(manifestId, packageFile); + + var definition = _packagingService.GetInstalledPackageById(packageId); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + packageId); + + _packagingService.InstallCompiledPackageData(definition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); } public override bool RequiresExecution(object model) { var installSteps = InstallStatusTracker.GetStatus().ToArray(); //this step relies on the preious one completed - because it has stored some information we need - if (installSteps.Any(x => x.Name == "StarterKitDownload" && x.AdditionalData.ContainsKey("manifestId")) == false) + if (installSteps.Any(x => x.Name == "StarterKitDownload" && x.AdditionalData.ContainsKey("packageId")) == false) { return false; } diff --git a/src/Umbraco.Web/Install/Models/InstallPackageModel.cs b/src/Umbraco.Web/Install/Models/InstallPackageModel.cs index 01eb368b6a..3ab74fa5e4 100644 --- a/src/Umbraco.Web/Install/Models/InstallPackageModel.cs +++ b/src/Umbraco.Web/Install/Models/InstallPackageModel.cs @@ -7,15 +7,15 @@ using System.Threading.Tasks; namespace Umbraco.Web.Install.Models { - + //fixme: do we need this? [Obsolete("This is only used for the obsolete controller InstallPackageController")] [DataContract(Name = "installPackage", Namespace = "")] public class InstallPackageModel { [DataMember(Name = "kitGuid")] public Guid KitGuid { get; set; } - [DataMember(Name = "manifestId")] - public int ManifestId { get; set; } + [DataMember(Name = "packageId")] + public int PackageId { get; set; } [DataMember(Name = "packageFile")] public string PackageFile { get; set; } diff --git a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs index 64ce51f539..d1d51e1fcc 100644 --- a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs +++ b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs @@ -47,25 +47,34 @@ namespace Umbraco.Web.Models public bool ContainsUnsecureFiles { get; set; } [DataMember(Name = "containsTemplateConflicts")] - public bool ContainsTemplateConflicts { get; set; } + public bool ContainsTemplateConflicts => ConflictingTemplateAliases != null && ConflictingTemplateAliases.Count > 0; [DataMember(Name = "containsStyleSheetConflicts")] - public bool ContainsStyleSheetConflicts { get; set; } + public bool ContainsStyleSheetConflicts => ConflictingStyleSheetNames != null && ConflictingStyleSheetNames.Count > 0; [DataMember(Name = "containsMacroConflict")] - public bool ContainsMacroConflict { get; set; } + public bool ContainsMacroConflict => ConflictingMacroAliases != null && ConflictingMacroAliases.Count > 0; + /// + /// Key value of name + alias + /// [DataMember(Name = "conflictingTemplateAliases")] public IDictionary ConflictingTemplateAliases { get; set; } + /// + /// Key value of name + alias + /// [DataMember(Name = "conflictingStyleSheetNames")] public IDictionary ConflictingStyleSheetNames { get; set; } + /// + /// Key value of name + alias + /// [DataMember(Name = "conflictingMacroAliases")] public IDictionary ConflictingMacroAliases { get; set; } - [DataMember(Name = "readMe")] - public string ReadMe { get; set; } + [DataMember(Name = "readme")] + public string Readme { get; set; } [DataMember(Name = "licenseUrl")] public string LicenseUrl { get; set; } diff --git a/src/Umbraco.Web/Models/PackageInstallModel.cs b/src/Umbraco.Web/Models/PackageInstallModel.cs index 7748129a40..1cf4a483ae 100644 --- a/src/Umbraco.Web/Models/PackageInstallModel.cs +++ b/src/Umbraco.Web/Models/PackageInstallModel.cs @@ -15,11 +15,10 @@ namespace Umbraco.Web.Models [DataMember(Name = "packageGuid")] public Guid PackageGuid { get; set; } + //TODO: Do we need this? [DataMember(Name = "repositoryGuid")] public Guid RepositoryGuid { get; set; } - [DataMember(Name = "temporaryDirectoryPath")] - public string TemporaryDirectoryPath { get; set; } [DataMember(Name = "zipFilePath")] public string ZipFilePath { get; set; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 1bd2860781..64e17af221 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1137,7 +1137,6 @@ - diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 286f41f61a..89dff406b0 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -1,803 +1,688 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Xml; -using System.Xml.Linq; -using System.Xml.XPath; -using ICSharpCode.SharpZipLib.Zip; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Events; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Packaging; -using Umbraco.Core.Services.Implement; -using File = System.IO.File; - -namespace Umbraco.Web._Legacy.Packager -{ - /// - /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. - /// - /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documentTypes (etc.) - /// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.) - /// - /// Partly implemented, import of packages is done, the export is *under construction*. - /// - /// - /// Ruben Verborgh 31/12/2007: I had to change some code, I marked my changes with "DATALAYER". - /// Reason: @@IDENTITY can't be used with the new datalayer. - /// I wasn't able to test the code, since I'm not aware how the code functions. - /// - public class Installer - { - private const string PackageServer = "packages.umbraco.org"; - - private readonly Dictionary _conflictingMacroAliases = new Dictionary(); - private readonly Dictionary _conflictingTemplateAliases = new Dictionary(); - private readonly Dictionary _conflictingStyleSheetNames = new Dictionary(); - - private readonly int _currentUserId = -1; - private static WebClient _webClient; - - - public string Name { get; private set; } - public string Version { get; private set; } - public string Url { get; private set; } - public string License { get; private set; } - public string LicenseUrl { get; private set; } - public string Author { get; private set; } - public string AuthorUrl { get; private set; } - public string ReadMe { get; private set; } - public string Control { get; private set; } - - public bool ContainsMacroConflict { get; private set; } - public IDictionary ConflictingMacroAliases => _conflictingMacroAliases; - - public bool ContainsUnsecureFiles { get; private set; } - public List UnsecureFiles { get; } = new List(); - - public bool ContainsTemplateConflicts { get; private set; } - public IDictionary ConflictingTemplateAliases => _conflictingTemplateAliases; - - public bool ContainsStyleSheeConflicts { get; private set; } - public IDictionary ConflictingStyleSheetNames => _conflictingStyleSheetNames; - - public int RequirementsMajor { get; private set; } - public int RequirementsMinor { get; private set; } - public int RequirementsPatch { get; private set; } - - public RequirementsType RequirementsType { get; private set; } - - public string IconUrl { get; private set; } - - /// - /// The xml of the compiled package - /// - public XDocument Config { get; private set; } - - /// - /// Constructor - /// - public Installer() - { - Initialize(); - } - - public Installer(int currentUserId) - { - Initialize(); - _currentUserId = currentUserId; - } - - private void Initialize() - { - ContainsTemplateConflicts = false; - ContainsUnsecureFiles = false; - ContainsMacroConflict = false; - ContainsStyleSheeConflicts = false; - } - - - - /// - /// Constructor - /// - /// The name of the package - /// The version of the package - /// The url to a descriptionpage - /// The license under which the package is released (preferably GPL ;)) - /// The url to a licensedescription - /// The original author of the package - /// The url to the Authors website - /// Umbraco version major - /// Umbraco version minor - /// Umbraco version patch - /// The readme text - /// The name of the usercontrol used to configure the package after install - /// - /// - public Installer(string name, string version, string url, string license, string licenseUrl, string author, string authorUrl, int requirementsMajor, int requirementsMinor, int requirementsPatch, string readme, string control, RequirementsType requirementsType, string iconUrl) - { - ContainsTemplateConflicts = false; - ContainsUnsecureFiles = false; - ContainsMacroConflict = false; - ContainsStyleSheeConflicts = false; - this.Name = name; - this.Version = version; - this.Url = url; - this.License = license; - this.LicenseUrl = licenseUrl; - this.RequirementsMajor = requirementsMajor; - this.RequirementsMinor = requirementsMinor; - this.RequirementsPatch = requirementsPatch; - this.RequirementsType = requirementsType; - this.Author = author; - this.AuthorUrl = authorUrl; - this.IconUrl = iconUrl; - ReadMe = readme; - this.Control = control; - } - - #region Public Methods - - /// - /// Imports the specified package - /// - /// Filename of the umbracopackage - /// true if the input file should be deleted after import - /// - public string Import(string inputFile, bool deleteFile) - { - using (Current.ProfilingLogger.DebugDuration( - $"Importing package file {inputFile}.", - $"Package file {inputFile} imported.")) - { - var tempDir = ""; - if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + inputFile))) - { - var fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + inputFile)); - // Check if the file is a valid package - if (fi.Extension.ToLower() == ".umb") - { - try - { - tempDir = UnPack(fi.FullName, deleteFile); - LoadConfig(tempDir); - } - catch (Exception ex) - { - Current.Logger.Error(ex, "Error importing file {FileName}", fi.FullName); - throw; - } - } - else - throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download."); - } - else - throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + inputFile) + "'"); - return tempDir; - } - - } - - /// - /// Imports the specified package - /// - /// Filename of the umbracopackage - /// - public string Import(string inputFile) - { - return Import(inputFile, true); - } - - public int CreateManifest(Guid guid) - { - //This is the new improved install rutine, which chops up the process into 3 steps, creating the manifest, moving files, and finally handling umb objects - - var parser = new CompiledPackageXmlParser(); - var def = parser.ToCompiledPackage(Config); - - //create a new entry in the installedPackages.config - var installedPackage = new PackageDefinition - { - Author = def.Author, - AuthorUrl = def.AuthorUrl, - Control = def.Control, - IconUrl = def.IconUrl, - License = def.License, - LicenseUrl = def.LicenseUrl, - Name = def.Name, - Readme = def.Readme, - UmbracoVersion = def.UmbracoVersion, - Url = def.Url, - Version = def.Version, - PackageId = guid - }; - - if (!Current.Services.PackagingService.SaveInstalledPackage(installedPackage)) - throw new InvalidOperationException("Could not save package definition"); - - return installedPackage.Id; - } - - public void InstallFiles(int packageId, string tempDir) - { - var parser = new CompiledPackageXmlParser(); - - using (Current.ProfilingLogger.DebugDuration( - "Installing package files for package id " + packageId + " into temp folder " + tempDir, - "Package file installation complete for package id " + packageId)) - { - //retrieve the manifest to continue installation - var insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); - - //TODO: Depending on some files, some files should be installed differently. - //i.e. if stylsheets should probably be installed via business logic, media items should probably use the media IFileSystem! - - // Move files - //string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath; - string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; - - var def = parser.ToCompiledPackage(Config); - - try - { - foreach (var f in def.Files) - { - var destPath = GetFileName(basePath, f.OriginalPath); - var sourceFile = GetFileName(tempDir, f.UniqueFileName); - var destFile = GetFileName(destPath, f.OriginalName); - - // Create the destination directory if it doesn't exist - if (Directory.Exists(destPath) == false) - Directory.CreateDirectory(destPath); - //If a file with this name exists, delete it - else if (File.Exists(destFile)) - File.Delete(destFile); - - // Copy the file - // SJ: Note - this used to do a move but some packages included the same file to be - // copied to multiple locations like so: - // - // - // my-icon.png - // /umbraco/Images/ - // my-icon.png - // - // - // my-icon.png - // /App_Plugins/MyPlugin/Images - // my-icon.png - // - // - // Since this file unzips as a flat list of files, moving the file the first time means - // that when you try to do that a second time, it would result in a FileNotFoundException - File.Copy(sourceFile, destFile); - - //PPH log file install - insPack.Files.Add(f.OriginalPath.EnsureEndsWith('/') + f.OriginalName); - - } - - // Once we're done copying, remove all the files - foreach (var f in def.Files) - { - var sourceFile = GetFileName(tempDir, f.UniqueFileName); - if (File.Exists(sourceFile)) - File.Delete(sourceFile); - } - } - catch (Exception ex) - { - Current.Logger.Error(ex, "Package install error"); - throw; - } - - // log that a user has install files - if (_currentUserId > -1) - { - Current.Services.AuditService.Add(AuditType.PackagerInstall, - _currentUserId, - -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Name, insPack.PackageId)); - } - - Current.Services.PackagingService.SaveInstalledPackage(insPack); - } - } - - public void InstallBusinessLogic(int packageId, string tempDir) - { - using (Current.ProfilingLogger.DebugDuration( - "Installing business logic for package id " + packageId + " into temp folder " + tempDir, - "Package business logic installation complete for package id " + packageId)) - { - PackageDefinition insPack; - try - { - //retrieve the manifest to continue installation - insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); - //bool saveNeeded = false; - - // Get current user, with a fallback - var currentUser = Current.Services.UserService.GetUserById(Constants.Security.SuperUserId); - - //TODO: Get rid of this entire class! Until then all packages will be installed by the admin user - - var rootElement = Config.Root; - var packagingService = Current.Services.PackagingService; - - //Perhaps it would have been a good idea to put the following into methods eh?!? - - #region DataTypes - var dataTypeElement = rootElement.Descendants("DataTypes").FirstOrDefault(); - if (dataTypeElement != null) - { - var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement, currentUser.Id); - foreach (var dataTypeDefinition in dataTypeDefinitions) - { - insPack.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); - } - } - #endregion - - #region Languages - var languageItemsElement = rootElement.Descendants("Languages").FirstOrDefault(); - if (languageItemsElement != null) - { - var insertedLanguages = packagingService.ImportLanguages(languageItemsElement); - foreach(var x in insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))) - insPack.Languages.Add(x); - } - - #endregion - - #region Dictionary items - var dictionaryItemsElement = rootElement.Descendants("DictionaryItems").FirstOrDefault(); - if (dictionaryItemsElement != null) - { - var insertedDictionaryItems = packagingService.ImportDictionaryItems(dictionaryItemsElement); - foreach (var x in insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))) - insPack.DictionaryItems.Add(x); - } - #endregion - - #region Macros - var macroItemsElement = rootElement.Descendants("Macros").FirstOrDefault(); - if (macroItemsElement != null) - { - var insertedMacros = packagingService.ImportMacros(macroItemsElement); - foreach (var x in insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))) - insPack.Macros.Add(x); - - } - #endregion - - #region Templates - var templateElement = rootElement.Descendants("Templates").FirstOrDefault(); - if (templateElement != null) - { - var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); - foreach (var template in templates) - { - insPack.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); - } - } - #endregion - - #region DocumentTypes - //Check whether the root element is a doc type rather then a complete package - var docTypeElement = rootElement.Name.LocalName.Equals("DocumentType") || - rootElement.Name.LocalName.Equals("DocumentTypes") - ? rootElement - : rootElement.Descendants("DocumentTypes").FirstOrDefault(); - - if (docTypeElement != null) - { - var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); - foreach (var contentType in contentTypes) - { - insPack.DocumentTypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } - } - #endregion - - #region Stylesheets - foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) - { - string stylesheetName = n.Element("Name")?.Value; - if (stylesheetName.IsNullOrWhiteSpace()) continue; - - var s = Current.Services.FileService.GetStylesheetByName(stylesheetName); - if (s == null) - { - var fileName = n.Element("FileName")?.Value; - if (fileName == null) continue; - var content = n.Element("Content")?.Value; - if (content == null) continue; - - s = new Stylesheet(fileName) { Content = content }; - Current.Services.FileService.SaveStylesheet(s); - } - - foreach (var prop in n.XPathSelectElements("Properties/Property")) - { - string alias = prop.Element("Alias")?.Value; - var sp = s.Properties.SingleOrDefault(p => p != null && p.Alias == alias); - string name = prop.Element("Name")?.Value; - if (sp == null) - { - //sp = StylesheetProperty.MakeNew( - // name, - // s, - // u); - - sp = new StylesheetProperty(name, "#" + name.ToSafeAlias(), ""); - s.AddProperty(sp); - } - else - { - //sp.Text = name; - //Changing the name requires removing the current property and then adding another new one - if (sp.Name != name) - { - s.RemoveProperty(sp.Name); - var newProp = new StylesheetProperty(name, sp.Alias, sp.Value); - s.AddProperty(newProp); - sp = newProp; - } - } - sp.Alias = alias; - sp.Value = prop.Element("Value")?.Value; - } - //s.saveCssToFile(); - Current.Services.FileService.SaveStylesheet(s); - - - - - insPack.Stylesheets.Add(s.Id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - #endregion - - #region Documents - var documentElement = rootElement.Descendants("DocumentSet").FirstOrDefault(); - if (documentElement != null) - { - var content = packagingService.ImportContent(documentElement, -1, currentUser.Id); - var firstContentItem = content.First(); - insPack.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); - } - #endregion - - #region Package Actions - foreach (var n in Config.Root.XPathSelectElements("Actions/Action")) - { - var undo = n.AttributeValue("undo"); - if (undo == null || undo == "true") - { - insPack.Actions += n.ToString(); - } - - //Run the actions tagged only for 'install' - var runat = n.AttributeValue("runat"); - - if (runat != null && runat == "install") - { - var alias = n.AttributeValue("alias"); - if (alias.IsNullOrWhiteSpace() == false) - { - Current.PackageActionRunner.RunPackageAction(insPack.Name, alias, n); - } - } - } - #endregion - - Current.Services.PackagingService.SaveInstalledPackage(insPack); - } - catch (Exception ex) - { - Current.Logger.Error(ex, "Error installing businesslogic"); - throw; - } - - OnPackageInstalled(insPack); - } - } - - /// - /// Remove the temp installation folder - /// - /// - /// - public void InstallCleanUp(int packageId, string tempDir) - { - if (Directory.Exists(tempDir)) - { - Directory.Delete(tempDir, true); - } - } - - /// - /// Reads the configuration of the package from the configuration xmldocument - /// - /// The folder to which the contents of the package is extracted - public void LoadConfig(string tempDir) - { - Config = XDocument.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); - - var parser = new CompiledPackageXmlParser(); - var def = parser.ToCompiledPackage(Config); - - Name = def.Name; - Version = def.Version; - Url = def.Url; - License = def.License; - LicenseUrl = def.LicenseUrl; - - RequirementsMajor = def.UmbracoVersion.Major; - RequirementsMinor = def.UmbracoVersion.Minor; - RequirementsPatch = def.UmbracoVersion.Build; - RequirementsType = def.UmbracoVersionRequirementsType; - IconUrl = def.IconUrl; - Author = def.Author; - AuthorUrl = def.AuthorUrl; - ReadMe = def.Readme; - Control = def.Control; - - var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; - var dllBinFiles = new List(); - - foreach (var f in def.Files) - { - var badFile = false; - var destPath = GetFileName(basePath, f.OriginalPath); - var orgName = f.OriginalName; - var destFile = GetFileName(destPath, orgName); - - if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) - { - badFile = true; - } - - if (destPath.ToLower().Contains(IOHelper.DirSepChar + "bin")) - { - badFile = true; - } - - if (destFile.ToLower().EndsWith(".dll")) - { - badFile = true; - dllBinFiles.Add(Path.Combine(tempDir, orgName)); - } - - if (badFile) - { - ContainsUnsecureFiles = true; - UnsecureFiles.Add(f.OriginalName); - } - } - - - - //this will check for existing macros with the same alias - //since we will not overwrite on import it's a good idea to inform the user what will be overwritten - foreach (var n in Config.Root.XPathSelectElements("//macro")) - { - var alias = n.Element("alias")?.Value; - if (!string.IsNullOrEmpty(alias)) - { - var m = Current.Services.MacroService.GetByAlias(alias); - if (m != null) - { - ContainsMacroConflict = true; - if (_conflictingMacroAliases.ContainsKey(m.Name) == false) - { - _conflictingMacroAliases.Add(m.Name, alias); - } - } - } - } - - foreach (var n in Config.Root.XPathSelectElements("Templates/Template")) - { - var alias = n.Element("Alias")?.Value; - if (!string.IsNullOrEmpty(alias)) - { - var t = Current.Services.FileService.GetTemplate(alias); - if (t != null) - { - ContainsTemplateConflicts = true; - if (_conflictingTemplateAliases.ContainsKey(t.Alias) == false) - { - _conflictingTemplateAliases.Add(t.Alias, alias); - } - } - } - } - - foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) - { - var alias = n.Element("Name")?.Value; - if (!string.IsNullOrEmpty(alias)) - { - var s = Current.Services.FileService.GetStylesheetByName(alias); - if (s != null) - { - ContainsStyleSheeConflicts = true; - if (_conflictingStyleSheetNames.ContainsKey(s.Alias) == false) - { - _conflictingStyleSheetNames.Add(s.Alias, alias); - } - } - } - } +//using System; +//using System.Collections.Generic; +//using System.Diagnostics; +//using System.Globalization; +//using System.IO; +//using System.Linq; +//using System.Net; +//using System.Xml; +//using System.Xml.Linq; +//using System.Xml.XPath; +//using ICSharpCode.SharpZipLib.Zip; +//using Umbraco.Core; +//using Umbraco.Core.Composing; +//using Umbraco.Core.Events; +//using Umbraco.Core.IO; +//using Umbraco.Core.Logging; +//using Umbraco.Core.Models; +//using Umbraco.Core.Models.Packaging; +//using Umbraco.Core.Packaging; +//using Umbraco.Core.Services.Implement; +//using File = System.IO.File; + +//namespace Umbraco.Web._Legacy.Packager +//{ +// /// +// /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. +// /// +// /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documentTypes (etc.) +// /// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.) +// /// +// /// Partly implemented, import of packages is done, the export is *under construction*. +// /// +// /// +// /// Ruben Verborgh 31/12/2007: I had to change some code, I marked my changes with "DATALAYER". +// /// Reason: @@IDENTITY can't be used with the new datalayer. +// /// I wasn't able to test the code, since I'm not aware how the code functions. +// /// +// public class Installer +// { +// private const string PackageServer = "packages.umbraco.org"; + +// private readonly Dictionary _conflictingMacroAliases = new Dictionary(); +// private readonly Dictionary _conflictingTemplateAliases = new Dictionary(); +// private readonly Dictionary _conflictingStyleSheetNames = new Dictionary(); + +// private readonly int _currentUserId = -1; +// private static WebClient _webClient; + + +// public string Name { get; private set; } +// public string Version { get; private set; } +// public string Url { get; private set; } +// public string License { get; private set; } +// public string LicenseUrl { get; private set; } +// public string Author { get; private set; } +// public string AuthorUrl { get; private set; } +// public string ReadMe { get; private set; } +// public string Control { get; private set; } + +// public bool ContainsMacroConflict { get; private set; } +// public IDictionary ConflictingMacroAliases => _conflictingMacroAliases; + +// public bool ContainsUnsecureFiles { get; private set; } +// public List UnsecureFiles { get; } = new List(); + +// public bool ContainsTemplateConflicts { get; private set; } +// public IDictionary ConflictingTemplateAliases => _conflictingTemplateAliases; + +// public bool ContainsStyleSheeConflicts { get; private set; } +// public IDictionary ConflictingStyleSheetNames => _conflictingStyleSheetNames; + +// public int RequirementsMajor { get; private set; } +// public int RequirementsMinor { get; private set; } +// public int RequirementsPatch { get; private set; } + +// public RequirementsType RequirementsType { get; private set; } + +// public string IconUrl { get; private set; } + +// /// +// /// The xml of the compiled package +// /// +// public XDocument Config { get; private set; } + +// /// +// /// Constructor +// /// +// public Installer() +// { +// Initialize(); +// } + +// public Installer(int currentUserId) +// { +// Initialize(); +// _currentUserId = currentUserId; +// } + +// private void Initialize() +// { +// ContainsTemplateConflicts = false; +// ContainsUnsecureFiles = false; +// ContainsMacroConflict = false; +// ContainsStyleSheeConflicts = false; +// } + + + +// /// +// /// Constructor +// /// +// /// The name of the package +// /// The version of the package +// /// The url to a descriptionpage +// /// The license under which the package is released (preferably GPL ;)) +// /// The url to a licensedescription +// /// The original author of the package +// /// The url to the Authors website +// /// Umbraco version major +// /// Umbraco version minor +// /// Umbraco version patch +// /// The readme text +// /// The name of the usercontrol used to configure the package after install +// /// +// /// +// public Installer(string name, string version, string url, string license, string licenseUrl, string author, string authorUrl, int requirementsMajor, int requirementsMinor, int requirementsPatch, string readme, string control, RequirementsType requirementsType, string iconUrl) +// { +// ContainsTemplateConflicts = false; +// ContainsUnsecureFiles = false; +// ContainsMacroConflict = false; +// ContainsStyleSheeConflicts = false; +// this.Name = name; +// this.Version = version; +// this.Url = url; +// this.License = license; +// this.LicenseUrl = licenseUrl; +// this.RequirementsMajor = requirementsMajor; +// this.RequirementsMinor = requirementsMinor; +// this.RequirementsPatch = requirementsPatch; +// this.RequirementsType = requirementsType; +// this.Author = author; +// this.AuthorUrl = authorUrl; +// this.IconUrl = iconUrl; +// ReadMe = readme; +// this.Control = control; +// } + +// #region Public Methods + +// /// +// /// Imports the specified package +// /// +// /// Filename of the umbracopackage +// /// true if the input file should be deleted after import +// /// +// public string Import(string inputFile, bool deleteFile) +// { +// using (Current.ProfilingLogger.DebugDuration( +// $"Importing package file {inputFile}.", +// $"Package file {inputFile} imported.")) +// { +// var tempDir = ""; +// if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + "/" + inputFile))) +// { +// var fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + "/" + inputFile)); +// // Check if the file is a valid package +// if (fi.Extension.ToLower() == ".umb") +// { +// try +// { +// tempDir = UnPack(fi.FullName, deleteFile); +// LoadConfig(tempDir); +// } +// catch (Exception ex) +// { +// Current.Logger.Error(ex, "Error importing file {FileName}", fi.FullName); +// throw; +// } +// } +// else +// throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download."); +// } +// else +// throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + inputFile) + "'"); +// return tempDir; +// } + +// } + +// /// +// /// Imports the specified package +// /// +// /// Filename of the umbracopackage +// /// +// public string Import(string inputFile) +// { +// return Import(inputFile, true); +// } + +// public int CreateManifest(Guid guid) +// { +// //This is the new improved install rutine, which chops up the process into 3 steps, creating the manifest, moving files, and finally handling umb objects + +// var parser = new CompiledPackageXmlParser(); +// var def = parser.ToCompiledPackage(Config); + +// //create a new entry in the installedPackages.config +// var installedPackage = new PackageDefinition +// { +// Author = def.Author, +// AuthorUrl = def.AuthorUrl, +// Control = def.Control, +// IconUrl = def.IconUrl, +// License = def.License, +// LicenseUrl = def.LicenseUrl, +// Name = def.Name, +// Readme = def.Readme, +// UmbracoVersion = def.UmbracoVersion, +// Url = def.Url, +// Version = def.Version, +// PackageId = guid +// }; + +// if (!Current.Services.PackagingService.SaveInstalledPackage(installedPackage)) +// throw new InvalidOperationException("Could not save package definition"); + +// return installedPackage.Id; +// } + +// public void InstallFiles(int packageId, string tempDir) +// { +// var parser = new CompiledPackageXmlParser(); + +// using (Current.ProfilingLogger.DebugDuration( +// "Installing package files for package id " + packageId + " into temp folder " + tempDir, +// "Package file installation complete for package id " + packageId)) +// { +// //retrieve the manifest to continue installation +// var insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); + +// //TODO: Depending on some files, some files should be installed differently. +// //i.e. if stylsheets should probably be installed via business logic, media items should probably use the media IFileSystem! + +// // Move files +// //string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath; +// string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; + +// var def = parser.ToCompiledPackage(Config); + +// try +// { +// foreach (var f in def.Files) +// { +// var destPath = GetFileName(basePath, f.OriginalPath); +// var sourceFile = GetFileName(tempDir, f.UniqueFileName); +// var destFile = GetFileName(destPath, f.OriginalName); + +// // Create the destination directory if it doesn't exist +// if (Directory.Exists(destPath) == false) +// Directory.CreateDirectory(destPath); +// //If a file with this name exists, delete it +// else if (File.Exists(destFile)) +// File.Delete(destFile); + +// // Copy the file +// // SJ: Note - this used to do a move but some packages included the same file to be +// // copied to multiple locations like so: +// // +// // +// // my-icon.png +// // /umbraco/Images/ +// // my-icon.png +// // +// // +// // my-icon.png +// // /App_Plugins/MyPlugin/Images +// // my-icon.png +// // +// // +// // Since this file unzips as a flat list of files, moving the file the first time means +// // that when you try to do that a second time, it would result in a FileNotFoundException +// File.Copy(sourceFile, destFile); + +// //PPH log file install +// insPack.Files.Add(f.OriginalPath.EnsureEndsWith('/') + f.OriginalName); + +// } + +// // Once we're done copying, remove all the files +// foreach (var f in def.Files) +// { +// var sourceFile = GetFileName(tempDir, f.UniqueFileName); +// if (File.Exists(sourceFile)) +// File.Delete(sourceFile); +// } +// } +// catch (Exception ex) +// { +// Current.Logger.Error(ex, "Package install error"); +// throw; +// } + +// // log that a user has install files +// if (_currentUserId > -1) +// { +// Current.Services.AuditService.Add(AuditType.PackagerInstall, +// _currentUserId, +// -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Name, insPack.PackageId)); +// } + +// Current.Services.PackagingService.SaveInstalledPackage(insPack); +// } +// } + +// public void InstallBusinessLogic(int packageId, string tempDir) +// { +// using (Current.ProfilingLogger.DebugDuration( +// "Installing business logic for package id " + packageId + " into temp folder " + tempDir, +// "Package business logic installation complete for package id " + packageId)) +// { +// PackageDefinition insPack; +// try +// { +// //retrieve the manifest to continue installation +// insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); +// //bool saveNeeded = false; + +// // Get current user, with a fallback +// var currentUser = Current.Services.UserService.GetUserById(Constants.Security.SuperUserId); + +// //TODO: Get rid of this entire class! Until then all packages will be installed by the admin user + +// var rootElement = Config.Root; +// var packagingService = Current.Services.PackagingService; + +// //Perhaps it would have been a good idea to put the following into methods eh?!? + +// #region DataTypes +// var dataTypeElement = rootElement.Descendants("DataTypes").FirstOrDefault(); +// if (dataTypeElement != null) +// { +// var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement, currentUser.Id); +// foreach (var dataTypeDefinition in dataTypeDefinitions) +// { +// insPack.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); +// } +// } +// #endregion + +// #region Languages +// var languageItemsElement = rootElement.Descendants("Languages").FirstOrDefault(); +// if (languageItemsElement != null) +// { +// var insertedLanguages = packagingService.ImportLanguages(languageItemsElement); +// foreach(var x in insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))) +// insPack.Languages.Add(x); +// } + +// #endregion + +// #region Dictionary items +// var dictionaryItemsElement = rootElement.Descendants("DictionaryItems").FirstOrDefault(); +// if (dictionaryItemsElement != null) +// { +// var insertedDictionaryItems = packagingService.ImportDictionaryItems(dictionaryItemsElement); +// foreach (var x in insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))) +// insPack.DictionaryItems.Add(x); +// } +// #endregion + +// #region Macros +// var macroItemsElement = rootElement.Descendants("Macros").FirstOrDefault(); +// if (macroItemsElement != null) +// { +// var insertedMacros = packagingService.ImportMacros(macroItemsElement); +// foreach (var x in insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))) +// insPack.Macros.Add(x); + +// } +// #endregion + +// #region Templates +// var templateElement = rootElement.Descendants("Templates").FirstOrDefault(); +// if (templateElement != null) +// { +// var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); +// foreach (var template in templates) +// { +// insPack.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); +// } +// } +// #endregion + +// #region DocumentTypes +// //Check whether the root element is a doc type rather then a complete package +// var docTypeElement = rootElement.Name.LocalName.Equals("DocumentType") || +// rootElement.Name.LocalName.Equals("DocumentTypes") +// ? rootElement +// : rootElement.Descendants("DocumentTypes").FirstOrDefault(); + +// if (docTypeElement != null) +// { +// var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); +// foreach (var contentType in contentTypes) +// { +// insPack.DocumentTypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); +// //saveNeeded = true; +// } +// } +// #endregion + +// #region Stylesheets +// foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) +// { +// string stylesheetName = n.Element("Name")?.Value; +// if (stylesheetName.IsNullOrWhiteSpace()) continue; + +// var s = Current.Services.FileService.GetStylesheetByName(stylesheetName); +// if (s == null) +// { +// var fileName = n.Element("FileName")?.Value; +// if (fileName == null) continue; +// var content = n.Element("Content")?.Value; +// if (content == null) continue; + +// s = new Stylesheet(fileName) { Content = content }; +// Current.Services.FileService.SaveStylesheet(s); +// } + +// foreach (var prop in n.XPathSelectElements("Properties/Property")) +// { +// string alias = prop.Element("Alias")?.Value; +// var sp = s.Properties.SingleOrDefault(p => p != null && p.Alias == alias); +// string name = prop.Element("Name")?.Value; +// if (sp == null) +// { +// //sp = StylesheetProperty.MakeNew( +// // name, +// // s, +// // u); + +// sp = new StylesheetProperty(name, "#" + name.ToSafeAlias(), ""); +// s.AddProperty(sp); +// } +// else +// { +// //sp.Text = name; +// //Changing the name requires removing the current property and then adding another new one +// if (sp.Name != name) +// { +// s.RemoveProperty(sp.Name); +// var newProp = new StylesheetProperty(name, sp.Alias, sp.Value); +// s.AddProperty(newProp); +// sp = newProp; +// } +// } +// sp.Alias = alias; +// sp.Value = prop.Element("Value")?.Value; +// } +// //s.saveCssToFile(); +// Current.Services.FileService.SaveStylesheet(s); + + + + +// insPack.Stylesheets.Add(s.Id.ToString(CultureInfo.InvariantCulture)); +// //saveNeeded = true; +// } + +// //if (saveNeeded) { insPack.Save(); saveNeeded = false; } +// #endregion + +// #region Documents +// var documentElement = rootElement.Descendants("DocumentSet").FirstOrDefault(); +// if (documentElement != null) +// { +// var content = packagingService.ImportContent(documentElement, -1, currentUser.Id); +// var firstContentItem = content.First(); +// insPack.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); +// } +// #endregion + +// #region Package Actions +// foreach (var n in Config.Root.XPathSelectElements("Actions/Action")) +// { +// var undo = n.AttributeValue("undo"); +// if (undo == null || undo == "true") +// { +// insPack.Actions += n.ToString(); +// } + +// //Run the actions tagged only for 'install' +// var runat = n.AttributeValue("runat"); + +// if (runat != null && runat == "install") +// { +// var alias = n.AttributeValue("alias"); +// if (alias.IsNullOrWhiteSpace() == false) +// { +// Current.PackageActionRunner.RunPackageAction(insPack.Name, alias, n); +// } +// } +// } +// #endregion + +// Current.Services.PackagingService.SaveInstalledPackage(insPack); +// } +// catch (Exception ex) +// { +// Current.Logger.Error(ex, "Error installing businesslogic"); +// throw; +// } + +// OnPackageInstalled(insPack); +// } +// } + +// /// +// /// Remove the temp installation folder +// /// +// /// +// /// +// public void InstallCleanUp(int packageId, string tempDir) +// { +// if (Directory.Exists(tempDir)) +// { +// Directory.Delete(tempDir, true); +// } +// } + +// /// +// /// Reads the configuration of the package from the configuration xmldocument +// /// +// /// The folder to which the contents of the package is extracted +// public void LoadConfig(string tempDir) +// { +// Config = XDocument.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); + +// var parser = new CompiledPackageXmlParser(); +// var def = parser.ToCompiledPackage(Config); + +// Name = def.Name; +// Version = def.Version; +// Url = def.Url; +// License = def.License; +// LicenseUrl = def.LicenseUrl; + +// RequirementsMajor = def.UmbracoVersion.Major; +// RequirementsMinor = def.UmbracoVersion.Minor; +// RequirementsPatch = def.UmbracoVersion.Build; +// RequirementsType = def.UmbracoVersionRequirementsType; +// IconUrl = def.IconUrl; +// Author = def.Author; +// AuthorUrl = def.AuthorUrl; +// ReadMe = def.Readme; +// Control = def.Control; + +// var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; +// var dllBinFiles = new List(); + +// foreach (var f in def.Files) +// { +// var badFile = false; +// var destPath = GetFileName(basePath, f.OriginalPath); +// var orgName = f.OriginalName; +// var destFile = GetFileName(destPath, orgName); + +// if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) +// { +// badFile = true; +// } + +// if (destPath.ToLower().Contains(IOHelper.DirSepChar + "bin")) +// { +// badFile = true; +// } + +// if (destFile.ToLower().EndsWith(".dll")) +// { +// badFile = true; +// dllBinFiles.Add(Path.Combine(tempDir, orgName)); +// } + +// if (badFile) +// { +// ContainsUnsecureFiles = true; +// UnsecureFiles.Add(f.OriginalName); +// } +// } + + + +// //this will check for existing macros with the same alias +// //since we will not overwrite on import it's a good idea to inform the user what will be overwritten +// foreach (var n in Config.Root.XPathSelectElements("//macro")) +// { +// var alias = n.Element("alias")?.Value; +// if (!string.IsNullOrEmpty(alias)) +// { +// var m = Current.Services.MacroService.GetByAlias(alias); +// if (m != null) +// { +// ContainsMacroConflict = true; +// if (_conflictingMacroAliases.ContainsKey(m.Name) == false) +// { +// _conflictingMacroAliases.Add(m.Name, alias); +// } +// } +// } +// } + +// foreach (var n in Config.Root.XPathSelectElements("Templates/Template")) +// { +// var alias = n.Element("Alias")?.Value; +// if (!string.IsNullOrEmpty(alias)) +// { +// var t = Current.Services.FileService.GetTemplate(alias); +// if (t != null) +// { +// ContainsTemplateConflicts = true; +// if (_conflictingTemplateAliases.ContainsKey(t.Alias) == false) +// { +// _conflictingTemplateAliases.Add(t.Alias, alias); +// } +// } +// } +// } + +// foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) +// { +// var alias = n.Element("Name")?.Value; +// if (!string.IsNullOrEmpty(alias)) +// { +// var s = Current.Services.FileService.GetStylesheetByName(alias); +// if (s != null) +// { +// ContainsStyleSheeConflicts = true; +// if (_conflictingStyleSheetNames.ContainsKey(s.Alias) == false) +// { +// _conflictingStyleSheetNames.Add(s.Alias, alias); +// } +// } +// } +// } - } +// } - /// - /// This uses the old method of fetching and only supports the packages.umbraco.org repository. - /// - /// - /// - public string Fetch(Guid Package) - { - // Check for package directory - if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages)) == false) - Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); +// /// +// /// This uses the old method of fetching and only supports the packages.umbraco.org repository. +// /// +// /// +// /// +// public string Fetch(Guid Package) +// { +// // Check for package directory +// if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages)) == false) +// Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - if (_webClient == null) - _webClient = new WebClient(); +// if (_webClient == null) +// _webClient = new WebClient(); - _webClient.DownloadFile( - "http://" + PackageServer + "/fetch?package=" + Package.ToString(), - IOHelper.MapPath(SystemDirectories.Packages + "/" + Package + ".umb")); +// _webClient.DownloadFile( +// "http://" + PackageServer + "/fetch?package=" + Package.ToString(), +// IOHelper.MapPath(SystemDirectories.Packages + "/" + Package + ".umb")); - return "packages\\" + Package + ".umb"; - } +// return "packages\\" + Package + ".umb"; +// } - #endregion +// #endregion - #region Private Methods +// private void OnPackageInstalled(PackageDefinition insPack) +// { +// // getting an InstallationSummary for sending to the PackagingService.ImportedPackage event +// var fileService = Current.Services.FileService; +// var macroService = Current.Services.MacroService; +// var contentTypeService = Current.Services.ContentTypeService; +// var dataTypeService = Current.Services.DataTypeService; +// var localizationService = Current.Services.LocalizationService; - /// - /// Gets the name of the file in the specified path. - /// Corrects possible problems with slashes that would result from a simple concatenation. - /// Can also be used to concatenate paths. - /// - /// The path. - /// Name of the file. - /// The name of the file in the specified path. - private static string GetFileName(string path, string fileName) - { - // virtual dir support - fileName = IOHelper.FindFile(fileName); +// var installationSummary = InstallationSummary.FromPackageDefinition(insPack, contentTypeService, dataTypeService, fileService, localizationService, macroService); +// installationSummary.PackageInstalled = true; - if (path.Contains("[$")) - { - //this is experimental and undocumented... - path = path.Replace("[$UMBRACO]", SystemDirectories.Umbraco); - path = path.Replace("[$CONFIG]", SystemDirectories.Config); - path = path.Replace("[$DATA]", SystemDirectories.Data); - } - - //to support virtual dirs we try to lookup the file... - path = IOHelper.FindFile(path); - - - - Debug.Assert(path != null && path.Length >= 1); - Debug.Assert(fileName != null && fileName.Length >= 1); - - path = path.Replace('/', '\\'); - fileName = fileName.Replace('/', '\\'); - - // Does filename start with a slash? Does path end with one? - bool fileNameStartsWithSlash = (fileName[0] == Path.DirectorySeparatorChar); - bool pathEndsWithSlash = (path[path.Length - 1] == Path.DirectorySeparatorChar); - - // Path ends with a slash - if (pathEndsWithSlash) - { - if (!fileNameStartsWithSlash) - // No double slash, just concatenate - return path + fileName; - return path + fileName.Substring(1); - } - if (fileNameStartsWithSlash) - // Required slash specified, just concatenate - return path + fileName; - return path + Path.DirectorySeparatorChar + fileName; - } - - private static string UnPack(string zipName, bool deleteFile) - { - // Unzip - - //the temp directory will be the package GUID - this keeps it consistent! - //the zipName is always the package Guid.umb - - var packageFileName = Path.GetFileNameWithoutExtension(zipName); - var packageId = Guid.NewGuid(); - Guid.TryParse(packageFileName, out packageId); - - string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + packageId.ToString(); - //clear the directory if it exists - if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); - Directory.CreateDirectory(tempDir); - - var s = new ZipInputStream(File.OpenRead(zipName)); - - ZipEntry theEntry; - while ((theEntry = s.GetNextEntry()) != null) - { - string fileName = Path.GetFileName(theEntry.Name); - - if (fileName != String.Empty) - { - FileStream streamWriter = File.Create(tempDir + Path.DirectorySeparatorChar + fileName); - - int size = 2048; - byte[] data = new byte[2048]; - while (true) - { - size = s.Read(data, 0, data.Length); - if (size > 0) - { - streamWriter.Write(data, 0, size); - } - else - { - break; - } - } - - streamWriter.Close(); - - } - } - - // Clean up - s.Close(); - - if (deleteFile) - { - File.Delete(zipName); - } - - - return tempDir; - - } - - #endregion - - - private void OnPackageInstalled(PackageDefinition insPack) - { - // getting an InstallationSummary for sending to the PackagingService.ImportedPackage event - var fileService = Current.Services.FileService; - var macroService = Current.Services.MacroService; - var contentTypeService = Current.Services.ContentTypeService; - var dataTypeService = Current.Services.DataTypeService; - var localizationService = Current.Services.LocalizationService; - - var installationSummary = InstallationSummary.FromPackageDefinition(insPack, contentTypeService, dataTypeService, fileService, localizationService, macroService); - installationSummary.PackageInstalled = true; - - var args = new ImportPackageEventArgs(installationSummary, insPack, false); - PackagingService.OnImportedPackage(args); - } - } -} +// var args = new ImportPackageEventArgs(installationSummary, insPack, false); +// PackagingService.OnImportedPackage(args); +// } +// } +//} diff --git a/src/Umbraco.Web/_Legacy/Packager/Settings.cs b/src/Umbraco.Web/_Legacy/Packager/Settings.cs deleted file mode 100644 index e88f18262f..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/Settings.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.IO; -using Umbraco.Core.IO; - -namespace Umbraco.Web._Legacy.Packager -{ - public class Settings - { - public static string InstalledPackagesSettings => SystemDirectories.Packages + IOHelper.DirSepChar + "installedPackages.config"; - - } - -} From 65e98928d4b5bd96b7ec919978abead1f39d4171 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 14 Jan 2019 17:46:12 +1100 Subject: [PATCH 074/223] Package data installation is now all migrated --- .../Composing/Composers/ServicesComposer.cs | 7 +- src/Umbraco.Core/Composing/Current.cs | 4 +- src/Umbraco.Core/Constants-Packaging.cs | 55 - src/Umbraco.Core/Events/ImportEventArgs.cs | 84 -- .../Models/Packaging/CompiledPackage.cs | 6 +- .../Models/Packaging/InstallationSummary.cs | 2 +- .../Packaging/CompiledPackageXmlParser.cs | 49 +- .../Packaging/ConflictingPackageData.cs | 12 +- .../Packaging/IPackageActionRunner.cs | 23 + .../Packaging/IPackageInstallation.cs | 3 +- .../Packaging/PackageActionRunner.cs | 3 +- .../Packaging/PackageDataInstallation.cs | 1144 +++++++++++++++ .../Packaging/PackageInstallation.cs | 306 +--- .../Services/IPackagingService.cs | 75 - .../Services/Implement/PackagingService.cs | 1303 +---------------- src/Umbraco.Core/Umbraco.Core.csproj | 4 +- .../Packaging/PackageInstallationTest.cs | 12 +- .../Services/Importing/PackageImportTests.cs | 126 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 27 +- src/Umbraco.Web/Composing/Current.cs | 2 +- .../Editors/ContentTypeController.cs | 29 +- .../Editors/PackageInstallController.cs | 5 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 - src/Umbraco.Web/_Legacy/Packager/Installer.cs | 688 --------- 24 files changed, 1424 insertions(+), 2546 deletions(-) delete mode 100644 src/Umbraco.Core/Constants-Packaging.cs delete mode 100644 src/Umbraco.Core/Events/ImportEventArgs.cs create mode 100644 src/Umbraco.Core/Packaging/IPackageActionRunner.cs create mode 100644 src/Umbraco.Core/Packaging/PackageDataInstallation.cs delete mode 100644 src/Umbraco.Web/_Legacy/Packager/Installer.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index ac8f4beeb0..a09462c806 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -59,18 +59,19 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(); - composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(factory => CreatePackageRepository(factory, "createdPackages.config")); composition.RegisterUnique(factory => CreatePackageRepository(factory, "installedPackages.config")); + composition.RegisterUnique(); composition.RegisterUnique(); var appRoot = new DirectoryInfo(IOHelper.GetRootDirectorySafe()); composition.RegisterUnique(factory => //factory required because we need to pass in a string path new PackageInstallation( - factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), + factory.GetInstance(), factory.GetInstance(), + factory.GetInstance(), factory.GetInstance(), SystemDirectories.Packages, appRoot, appRoot)); diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index 4bed76d86f..5c8351924f 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -162,8 +162,8 @@ namespace Umbraco.Core.Composing internal static PackageActionCollection PackageActions => Factory.GetInstance(); - internal static PackageActionRunner PackageActionRunner - => Factory.GetInstance(); + internal static IPackageActionRunner PackageActionRunner + => Factory.GetInstance(); internal static PropertyValueConverterCollection PropertyValueConverters => Factory.GetInstance(); diff --git a/src/Umbraco.Core/Constants-Packaging.cs b/src/Umbraco.Core/Constants-Packaging.cs deleted file mode 100644 index 37f2c23fa3..0000000000 --- a/src/Umbraco.Core/Constants-Packaging.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Umbraco.Core -{ - public static partial class Constants - { - /// - /// Defines the constants used for Umbraco packages in the package.config xml - /// - public static class Packaging - { - public const string UmbPackageNodeName = "umbPackage"; - public const string DataTypesNodeName = "DataTypes"; - public const string PackageXmlFileName = "package.xml"; - public const string UmbracoPackageExtention = ".umb"; - public const string DataTypeNodeName = "DataType"; - public const string LanguagesNodeName = "Languages"; - public const string FilesNodeName = "files"; - public const string StylesheetsNodeName = "Stylesheets"; - public const string TemplatesNodeName = "Templates"; - public const string NameNodeName = "Name"; - public const string TemplateNodeName = "Template"; - public const string AliasNodeNameSmall = "alias"; - public const string AliasNodeNameCapital = "Alias"; - public const string DictionaryItemsNodeName = "DictionaryItems"; - public const string DictionaryItemNodeName = "DictionaryItem"; - public const string MacrosNodeName = "Macros"; - public const string DocumentsNodeName = "Documents"; - public const string DocumentSetNodeName = "DocumentSet"; - public const string DocumentTypesNodeName = "DocumentTypes"; - public const string DocumentTypeNodeName = "DocumentType"; - public const string FileNodeName = "file"; - public const string OrgNameNodeName = "orgName"; - public const string OrgPathNodeName = "orgPath"; - public const string GuidNodeName = "guid"; - public const string StylesheetNodeName = "styleSheet"; - public const string MacroNodeName = "macro"; - public const string InfoNodeName = "info"; - public const string PackageRequirementsMajorXpath = "./package/requirements/major"; - public const string PackageRequirementsMinorXpath = "./package/requirements/minor"; - public const string PackageRequirementsPatchXpath = "./package/requirements/patch"; - public const string PackageNameXpath = "./package/name"; - public const string PackageVersionXpath = "./package/version"; - public const string PackageUrlXpath = "./package/url"; - public const string PackageLicenseXpath = "./package/license"; - public const string PackageLicenseXpathUrlAttribute = "url"; - public const string AuthorNameXpath = "./author/name"; - public const string AuthorWebsiteXpath = "./author/website"; - public const string ReadmeXpath = "./readme"; - public const string ControlNodeName = "control"; - public const string ActionNodeName = "Action"; - public const string ActionsNodeName = "Actions"; - public const string UndoNodeAttribute = "undo"; - public const string RunatNodeAttribute = "runat"; - } - } -} diff --git a/src/Umbraco.Core/Events/ImportEventArgs.cs b/src/Umbraco.Core/Events/ImportEventArgs.cs deleted file mode 100644 index fb8f7d4936..0000000000 --- a/src/Umbraco.Core/Events/ImportEventArgs.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Umbraco.Core.Events -{ - public class ImportEventArgs : CancellableEnumerableObjectEventArgs, IEquatable> - { - /// - /// Constructor accepting an XElement with the xml being imported - /// - /// - public ImportEventArgs(XElement xml) : base(new List(), true) - { - Xml = xml; - } - - /// - /// Constructor accepting a list of entities and an XElement with the imported xml - /// - /// - /// - /// - public ImportEventArgs(IEnumerable eventObject, XElement xml, bool canCancel) - : base(eventObject, canCancel) - { - Xml = xml; - } - - protected ImportEventArgs(IEnumerable eventObject, bool canCancel) : base(eventObject, canCancel) - { - } - - protected ImportEventArgs(IEnumerable eventObject) : base(eventObject) - { - } - - /// - /// Returns all entities that were imported during the operation - /// - public IEnumerable ImportedEntities - { - get { return EventObject; } - } - - /// - /// Returns the xml relating to the import event - /// - public XElement Xml { get; private set; } - - public bool Equals(ImportEventArgs other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return base.Equals(other) && Equals(Xml, other.Xml); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((ImportEventArgs) obj); - } - - public override int GetHashCode() - { - unchecked - { - return (base.GetHashCode() * 397) ^ (Xml != null ? Xml.GetHashCode() : 0); - } - } - - public static bool operator ==(ImportEventArgs left, ImportEventArgs right) - { - return Equals(left, right); - } - - public static bool operator !=(ImportEventArgs left, ImportEventArgs right) - { - return !Equals(left, right); - } - } -} diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index 96159d1bbf..266c1f5518 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -34,7 +34,11 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable Macros { get; set; } //fixme: make strongly typed public IEnumerable Templates { get; set; } //fixme: make strongly typed public IEnumerable Stylesheets { get; set; } //fixme: make strongly typed - + public IEnumerable DataTypes { get; set; } //fixme: make strongly typed + public IEnumerable Languages { get; set; } //fixme: make strongly typed + public IEnumerable DictionaryItems { get; set; } //fixme: make strongly typed + public IEnumerable DocumentTypes { get; set; } //fixme: make strongly typed + public IEnumerable Documents { get; set; } //fixme: make strongly typed } public class CompiledPackageFile diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index 1405259da2..b14e3d2a92 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable MacrosInstalled { get; set; } = Enumerable.Empty(); public IEnumerable FilesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable TemplatesInstalled { get; set; } = Enumerable.Empty(); - public IEnumerable ContentTypesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable DocumentTypesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable StylesheetsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); public IEnumerable Actions { get; set; } = Enumerable.Empty(); diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 44dbded5d2..76f206f478 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Packaging { if (xml == null) throw new ArgumentNullException(nameof(xml)); if (xml.Root == null) throw new ArgumentException(nameof(xml), "The xml document is invalid"); - if (xml.Root.Name != Constants.Packaging.UmbPackageNodeName) throw new FormatException("The xml document is invalid"); + if (xml.Root.Name != "umbPackage") throw new FormatException("The xml document is invalid"); var info = xml.Root.Element("info"); if (info == null) throw new FormatException("The xml document is invalid"); @@ -53,7 +53,6 @@ namespace Umbraco.Core.Packaging UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type")), Control = package.Element("control")?.Value, Actions = xml.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value - Files = xml.Root.Element("files")?.Elements("file")?.Select(x => new CompiledPackageFile { UniqueFileName = x.Element("guid")?.Value, @@ -64,7 +63,11 @@ namespace Umbraco.Core.Packaging Macros = xml.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), Templates = xml.Element("Templates")?.Elements("Template") ?? Enumerable.Empty(), Stylesheets = xml.Element("Stylesheets")?.Elements("styleSheet") ?? Enumerable.Empty(), - + DataTypes = xml.Element("DataTypes")?.Elements("DataType") ?? Enumerable.Empty(), + Languages = xml.Element("Languages")?.Elements("Language") ?? Enumerable.Empty(), + DictionaryItems = xml.Element("DictionaryItems")?.Elements("DictionaryItem") ?? Enumerable.Empty(), + DocumentTypes = xml.Element("DocumentTypes")?.Elements("DocumentType") ?? Enumerable.Empty(), + Documents = xml.Element("Documents")?.Elements("DocumentSet") ?? Enumerable.Empty(), }; def.Warnings = GetPreInstallWarnings(def, applicationRootFolder); @@ -133,9 +136,8 @@ namespace Umbraco.Core.Packaging { return pathElement.TrimStart(new[] { '\\', '/', '~' }).Replace("/", "\\"); } - - //fixme: This is duplicated in the parser - public static string UpdatePathPlaceholders(string path) + + private static string UpdatePathPlaceholders(string path) { if (path.Contains("[$")) { @@ -146,5 +148,40 @@ namespace Umbraco.Core.Packaging } return path; } + + public IEnumerable GetPackageActions(XElement actionsElement, string packageName) + { + if (actionsElement == null) { return new PackageAction[0]; } + + if (string.Equals("Actions", actionsElement.Name.LocalName) == false) + throw new ArgumentException($"Must be \"Actions\" as root", nameof(actionsElement)); + + return actionsElement.Elements("Action") + .Select(elemet => + { + var aliasAttr = elemet.Attribute("Alias"); + if (aliasAttr == null) + throw new ArgumentException("missing \"Alias\" atribute in alias element", nameof(actionsElement)); + + var packageAction = new PackageAction + { + XmlData = elemet, + Alias = aliasAttr.Value, + PackageName = packageName, + }; + + + var attr = elemet.Attribute("runat"); + + if (attr != null && Enum.TryParse(attr.Value, true, out ActionRunAt runAt)) { packageAction.RunAt = runAt; } + + attr = elemet.Attribute("undo"); + + if (attr != null && bool.TryParse(attr.Value, out var undo)) { packageAction.Undo = undo; } + + + return packageAction; + }).ToArray(); + } } } diff --git a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs index 401d3b6a85..a37195806e 100644 --- a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs +++ b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs @@ -23,9 +23,9 @@ namespace Umbraco.Core.Packaging return stylesheetNodes .Select(n => { - var xElement = n.Element(Constants.Packaging.NameNodeName); + var xElement = n.Element("Name"); if (xElement == null) - throw new FormatException($"Missing \"{Constants.Packaging.NameNodeName}\" element"); + throw new FormatException("Missing \"Name\" element"); return _fileService.GetStylesheetByName(xElement.Value) as IFile; }) @@ -37,9 +37,9 @@ namespace Umbraco.Core.Packaging return templateNodes .Select(n => { - var xElement = n.Element(Constants.Packaging.AliasNodeNameCapital) ?? n.Element(Constants.Packaging.AliasNodeNameSmall); + var xElement = n.Element("Alias") ?? n.Element("alias"); if (xElement == null) - throw new FormatException($"missing a \"{Constants.Packaging.AliasNodeNameCapital}\" element"); + throw new FormatException("missing a \"Alias\" element"); return _fileService.GetTemplate(xElement.Value); }) @@ -51,9 +51,9 @@ namespace Umbraco.Core.Packaging return macroNodes .Select(n => { - var xElement = n.Element(Constants.Packaging.AliasNodeNameSmall) ?? n.Element(Constants.Packaging.AliasNodeNameCapital); + var xElement = n.Element("alias") ?? n.Element("Alias"); if (xElement == null) - throw new FormatException($"missing a \"{Constants.Packaging.AliasNodeNameSmall}\" element in {Constants.Packaging.AliasNodeNameSmall} element"); + throw new FormatException("missing a \"alias\" element in alias element"); return _macroService.GetByAlias(xElement.Value); }) diff --git a/src/Umbraco.Core/Packaging/IPackageActionRunner.cs b/src/Umbraco.Core/Packaging/IPackageActionRunner.cs new file mode 100644 index 0000000000..d5c6327115 --- /dev/null +++ b/src/Umbraco.Core/Packaging/IPackageActionRunner.cs @@ -0,0 +1,23 @@ +using System.Xml.Linq; + +namespace Umbraco.Core.Packaging +{ + public interface IPackageActionRunner + { + /// + /// Runs the package action with the specified action alias. + /// + /// Name of the package. + /// The action alias. + /// The action XML. + void RunPackageAction(string packageName, string actionAlias, XElement actionXml); + + /// + /// Undos the package action with the specified action alias. + /// + /// Name of the package. + /// The action alias. + /// The action XML. + void UndoPackageAction(string packageName, string actionAlias, XElement actionXml); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 8ef3546c3d..83a21dcd2f 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -4,9 +4,8 @@ using Umbraco.Core.Models.Packaging; namespace Umbraco.Core.Packaging { - internal interface IPackageInstallation + public interface IPackageInstallation { - /// /// Installs a packages data and entities /// diff --git a/src/Umbraco.Core/Packaging/PackageActionRunner.cs b/src/Umbraco.Core/Packaging/PackageActionRunner.cs index 64b913989c..37103b0473 100644 --- a/src/Umbraco.Core/Packaging/PackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/PackageActionRunner.cs @@ -5,11 +5,10 @@ using Umbraco.Core._Legacy.PackageActions; namespace Umbraco.Core.Packaging { - /// /// Package actions are executed on packge install / uninstall. /// - public sealed class PackageActionRunner + internal class PackageActionRunner : IPackageActionRunner { private readonly ILogger _logger; private readonly PackageActionCollection _packageActions; diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs new file mode 100644 index 0000000000..8ef99502c8 --- /dev/null +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -0,0 +1,1144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web; +using System.Xml.Linq; +using System.Xml.XPath; +using Umbraco.Core.Collections; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Entities; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; + +namespace Umbraco.Core.Packaging +{ + internal class PackageDataInstallation + { + private readonly ILogger _logger; + private readonly IFileService _fileService; + private readonly IMacroService _macroService; + private readonly ILocalizationService _localizationService; + private readonly IDataTypeService _dataTypeService; + private readonly PropertyEditorCollection _propertyEditors; + private readonly IEntityService _entityService; + private readonly IContentTypeService _contentTypeService; + private readonly IContentService _contentService; + + public PackageDataInstallation(ILogger logger, IFileService fileService, IMacroService macroService, ILocalizationService localizationService, + IDataTypeService dataTypeService, IEntityService entityService, IContentTypeService contentTypeService, + IContentService contentService, PropertyEditorCollection propertyEditors) + { + _logger = logger; + _fileService = fileService; + _macroService = macroService; + _localizationService = localizationService; + _dataTypeService = dataTypeService; + _propertyEditors = propertyEditors; + _entityService = entityService; + _contentTypeService = contentTypeService; + _contentService = contentService; + } + + #region Content + + + public IEnumerable ImportContent(IEnumerable element, IDictionary importedDocumentTypes, int userId) + { + return element.Elements("DocumentSet").SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId)); + } + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional parent Id for the content being imported + /// A dictionary of already imported document types (basically used as a cache) + /// Optional Id of the user performing the import + /// An enumrable list of generated content + public IEnumerable ImportContent(XElement element, int parentId, IDictionary importedDocumentTypes, int userId) + { + var name = element.Name.LocalName; + if (name.Equals("DocumentSet")) + { + //This is a regular deep-structured import + var roots = from doc in element.Elements() + where (string)doc.Attribute("isDoc") == "" + select doc; + + var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList(); + if (contents.Any()) + _contentService.Save(contents, userId); + + return contents; + } + + var attribute = element.Attribute("isDoc"); + if (attribute != null) + { + //This is a single doc import + var elements = new List { element }; + var contents = ParseDocumentRootXml(elements, parentId, importedDocumentTypes).ToList(); + if (contents.Any()) + _contentService.Save(contents, userId); + + return contents; + } + + throw new ArgumentException( + "The passed in XElement is not valid! It does not contain a root element called " + + "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); + } + + private IEnumerable ParseDocumentRootXml(IEnumerable roots, int parentId, IDictionary importedContentTypes) + { + var contents = new List(); + foreach (var root in roots) + { + var contentTypeAlias = root.Name.LocalName; + + if (!importedContentTypes.ContainsKey(contentTypeAlias)) + { + var contentType = FindContentTypeByAlias(contentTypeAlias); + importedContentTypes.Add(contentTypeAlias, contentType); + } + + var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], null, parentId); + contents.Add(content); + + var children = (from child in root.Elements() + where (string)child.Attribute("isDoc") == "" + select child) + .ToList(); + if (children.Any()) + contents.AddRange(CreateContentFromXml(children, content, importedContentTypes)); + } + return contents; + } + + private IEnumerable CreateContentFromXml(IEnumerable children, IContent parent, IDictionary importedContentTypes) + { + var list = new List(); + foreach (var child in children) + { + string contentTypeAlias = child.Name.LocalName; + + if (importedContentTypes.ContainsKey(contentTypeAlias) == false) + { + var contentType = FindContentTypeByAlias(contentTypeAlias); + importedContentTypes.Add(contentTypeAlias, contentType); + } + + //Create and add the child to the list + var content = CreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default); + list.Add(content); + + //Recursive call + XElement child1 = child; + var grandChildren = (from grand in child1.Elements() + where (string)grand.Attribute("isDoc") == "" + select grand).ToList(); + + if (grandChildren.Any()) + list.AddRange(CreateContentFromXml(grandChildren, content, importedContentTypes)); + } + + return list; + } + + private IContent CreateContentFromXml(XElement element, IContentType contentType, IContent parent, int parentId) + { + var id = element.Attribute("id").Value; + var level = element.Attribute("level").Value; + var sortOrder = element.Attribute("sortOrder").Value; + var nodeName = element.Attribute("nodeName").Value; + var path = element.Attribute("path").Value; + //TODO: Shouldn't we be using this value??? + var template = element.Attribute("template").Value; + var key = Guid.Empty; + + var properties = from property in element.Elements() + where property.Attribute("isDoc") == null + select property; + + IContent content = parent == null + ? new Content(nodeName, parentId, contentType) + { + Level = int.Parse(level), + SortOrder = int.Parse(sortOrder) + } + : new Content(nodeName, parent, contentType) + { + Level = int.Parse(level), + SortOrder = int.Parse(sortOrder) + }; + + if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key)) + { + // update the Guid (for UDI support) + content.Key = key; + } + + foreach (var property in properties) + { + string propertyTypeAlias = property.Name.LocalName; + if (content.HasProperty(propertyTypeAlias)) + { + var propertyValue = property.Value; + + var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias); + + //set property value + content.SetValue(propertyTypeAlias, propertyValue); + } + } + + return content; + } + + #endregion + + #region ContentTypes + + public IEnumerable ImportDocumentType(XElement docTypeElement, int userId) + { + return ImportDocumentTypes(new []{ docTypeElement }, userId); + } + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional id of the User performing the operation. Default is zero (admin). + /// An enumrable list of generated ContentTypes + public IEnumerable ImportDocumentTypes(IEnumerable docTypeElements, int userId) + { + return ImportDocumentTypes(docTypeElements.ToList(), true, userId); + } + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Boolean indicating whether or not to import the + /// Optional id of the User performing the operation. Default is zero (admin). + /// An enumrable list of generated ContentTypes + public IEnumerable ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId) + { + var importedContentTypes = new Dictionary(); + + //When you are importing a single doc type we have to assume that the depedencies are already there. + //Otherwise something like uSync won't work. + var graph = new TopoGraph>(x => x.Key, x => x.Dependencies); + var isSingleDocTypeImport = unsortedDocumentTypes.Count == 1; + + var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes); + + if (isSingleDocTypeImport == false) + { + //NOTE Here we sort the doctype XElements based on dependencies + //before creating the doc types - this should also allow for a better structure/inheritance support. + foreach (var documentType in unsortedDocumentTypes) + { + var elementCopy = documentType; + var infoElement = elementCopy.Element("Info"); + var dependencies = new HashSet(); + + //Add the Master as a dependency + if (string.IsNullOrEmpty((string)infoElement.Element("Master")) == false) + { + dependencies.Add(infoElement.Element("Master").Value); + } + + //Add compositions as dependencies + var compositionsElement = infoElement.Element("Compositions"); + if (compositionsElement != null && compositionsElement.HasElements) + { + var compositions = compositionsElement.Elements("Composition"); + if (compositions.Any()) + { + foreach (var composition in compositions) + { + dependencies.Add(composition.Value); + } + } + } + + graph.AddItem(TopoGraph.CreateNode(infoElement.Element("Alias").Value, elementCopy, dependencies.ToArray())); + } + } + + //Sorting the Document Types based on dependencies - if its not a single doc type import ref. #U4-5921 + var documentTypes = isSingleDocTypeImport + ? unsortedDocumentTypes.ToList() + : graph.GetSortedItems().Select(x => x.Item).ToList(); + + //Iterate the sorted document types and create them as IContentType objects + foreach (var documentType in documentTypes) + { + var alias = documentType.Element("Info").Element("Alias").Value; + if (importedContentTypes.ContainsKey(alias) == false) + { + var contentType = _contentTypeService.Get(alias); + importedContentTypes.Add(alias, contentType == null + ? CreateContentTypeFromXml(documentType, importedContentTypes) + : UpdateContentTypeFromXml(documentType, contentType, importedContentTypes)); + } + } + + foreach (var contentType in importedContentTypes) + { + var ct = contentType.Value; + if (importedFolders.ContainsKey(ct.Alias)) + { + ct.ParentId = importedFolders[ct.Alias]; + } + } + + //Save the newly created/updated IContentType objects + var list = importedContentTypes.Select(x => x.Value).ToList(); + _contentTypeService.Save(list, userId); + + //Now we can finish the import by updating the 'structure', + //which requires the doc types to be saved/available in the db + if (importStructure) + { + var updatedContentTypes = new List(); + //Update the structure here - we can't do it untill all DocTypes have been created + foreach (var documentType in documentTypes) + { + var alias = documentType.Element("Info").Element("Alias").Value; + var structureElement = documentType.Element("Structure"); + //Ensure that we only update ContentTypes which has actual structure-elements + if (structureElement == null || structureElement.Elements("DocumentType").Any() == false) continue; + + var updated = UpdateContentTypesStructure(importedContentTypes[alias], structureElement, importedContentTypes); + updatedContentTypes.Add(updated); + } + //Update ContentTypes with a newly added structure/list of allowed children + if (updatedContentTypes.Any()) + _contentTypeService.Save(updatedContentTypes, userId); + } + + return list; + } + + private Dictionary CreateContentTypeFolderStructure(IEnumerable unsortedDocumentTypes) + { + var importedFolders = new Dictionary(); + foreach (var documentType in unsortedDocumentTypes) + { + var foldersAttribute = documentType.Attribute("Folders"); + var infoElement = documentType.Element("Info"); + if (foldersAttribute != null && infoElement != null + //don't import any folder if this is a child doc type - the parent doc type will need to + //exist which contains it's folders + && ((string)infoElement.Element("Master")).IsNullOrWhiteSpace()) + { + var alias = documentType.Element("Info").Element("Alias").Value; + var folders = foldersAttribute.Value.Split('/'); + var rootFolder = HttpUtility.UrlDecode(folders[0]); + //level 1 = root level folders, there can only be one with the same name + var current = _contentTypeService.GetContainers(rootFolder, 1).FirstOrDefault(); + + if (current == null) + { + var tryCreateFolder = _contentTypeService.CreateContainer(-1, rootFolder); + if (tryCreateFolder == false) + { + _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); + throw tryCreateFolder.Exception; + } + var rootFolderId = tryCreateFolder.Result.Entity.Id; + current = _contentTypeService.GetContainer(rootFolderId); + } + + importedFolders.Add(alias, current.Id); + + for (var i = 1; i < folders.Length; i++) + { + var folderName = HttpUtility.UrlDecode(folders[i]); + current = CreateContentTypeChildFolder(folderName, current); + importedFolders[alias] = current.Id; + } + } + } + + return importedFolders; + } + + private EntityContainer CreateContentTypeChildFolder(string folderName, IUmbracoEntity current) + { + var children = _entityService.GetChildren(current.Id).ToArray(); + var found = children.Any(x => x.Name.InvariantEquals(folderName)); + if (found) + { + var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id; + return _contentTypeService.GetContainer(containerId); + } + + var tryCreateFolder = _contentTypeService.CreateContainer(current.Id, folderName); + if (tryCreateFolder == false) + { + _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); + throw tryCreateFolder.Exception; + } + return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); + } + + private IContentType CreateContentTypeFromXml(XElement documentType, IReadOnlyDictionary importedContentTypes) + { + var infoElement = documentType.Element("Info"); + + //Name of the master corresponds to the parent + var masterElement = infoElement.Element("Master"); + IContentType parent = null; + if (masterElement != null) + { + var masterAlias = masterElement.Value; + parent = importedContentTypes.ContainsKey(masterAlias) + ? importedContentTypes[masterAlias] + : _contentTypeService.Get(masterAlias); + } + + var alias = infoElement.Element("Alias").Value; + var contentType = parent == null + ? new ContentType(-1) { Alias = alias } + : new ContentType(parent, alias); + + if (parent != null) + contentType.AddContentType(parent); + + return UpdateContentTypeFromXml(documentType, contentType, importedContentTypes); + } + + private IContentType UpdateContentTypeFromXml(XElement documentType, IContentType contentType, IReadOnlyDictionary importedContentTypes) + { + var infoElement = documentType.Element("Info"); + var defaultTemplateElement = infoElement.Element("DefaultTemplate"); + + contentType.Name = infoElement.Element("Name").Value; + contentType.Icon = infoElement.Element("Icon").Value; + contentType.Thumbnail = infoElement.Element("Thumbnail").Value; + contentType.Description = infoElement.Element("Description").Value; + + //NOTE AllowAtRoot is a new property in the package xml so we need to verify it exists before using it. + var allowAtRoot = infoElement.Element("AllowAtRoot"); + if (allowAtRoot != null) + contentType.AllowedAsRoot = allowAtRoot.Value.InvariantEquals("true"); + + //NOTE IsListView is a new property in the package xml so we need to verify it exists before using it. + var isListView = infoElement.Element("IsListView"); + if (isListView != null) + contentType.IsContainer = isListView.Value.InvariantEquals("true"); + + //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set + var masterElement = infoElement.Element("Master"); + if (masterElement != null) + { + var masterAlias = masterElement.Value; + IContentType parent = importedContentTypes.ContainsKey(masterAlias) + ? importedContentTypes[masterAlias] + : _contentTypeService.Get(masterAlias); + + contentType.SetParent(parent); + } + + //Update Compositions on the ContentType to ensure that they are as is defined in the package xml + var compositionsElement = infoElement.Element("Compositions"); + if (compositionsElement != null && compositionsElement.HasElements) + { + var compositions = compositionsElement.Elements("Composition"); + if (compositions.Any()) + { + foreach (var composition in compositions) + { + var compositionAlias = composition.Value; + var compositionContentType = importedContentTypes.ContainsKey(compositionAlias) + ? importedContentTypes[compositionAlias] + : _contentTypeService.Get(compositionAlias); + var added = contentType.AddContentType(compositionContentType); + } + } + } + + UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement); + UpdateContentTypesTabs(contentType, documentType.Element("Tabs")); + UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties")); + + return contentType; + } + + private void UpdateContentTypesAllowedTemplates(IContentType contentType, + XElement allowedTemplatesElement, XElement defaultTemplateElement) + { + if (allowedTemplatesElement != null && allowedTemplatesElement.Elements("Template").Any()) + { + var allowedTemplates = contentType.AllowedTemplates.ToList(); + foreach (var templateElement in allowedTemplatesElement.Elements("Template")) + { + var alias = templateElement.Value; + var template = _fileService.GetTemplate(alias.ToSafeAlias()); + if (template != null) + { + if (allowedTemplates.Any(x => x.Id == template.Id)) continue; + allowedTemplates.Add(template); + } + else + { + _logger.Warn("Packager: Error handling allowed templates. Template with alias '{TemplateAlias}' could not be found.", alias); + } + } + + contentType.AllowedTemplates = allowedTemplates; + } + + if (string.IsNullOrEmpty((string)defaultTemplateElement) == false) + { + var defaultTemplate = _fileService.GetTemplate(defaultTemplateElement.Value.ToSafeAlias()); + if (defaultTemplate != null) + { + contentType.SetDefaultTemplate(defaultTemplate); + } + else + { + _logger.Warn("Packager: Error handling default template. Default template with alias '{DefaultTemplateAlias}' could not be found.", defaultTemplateElement.Value); + } + } + } + + private void UpdateContentTypesTabs(IContentType contentType, XElement tabElement) + { + if (tabElement == null) + return; + + var tabs = tabElement.Elements("Tab"); + foreach (var tab in tabs) + { + var id = tab.Element("Id").Value;//Do we need to use this for tracking? + var caption = tab.Element("Caption").Value; + + if (contentType.PropertyGroups.Contains(caption) == false) + { + contentType.AddPropertyGroup(caption); + + } + + int sortOrder; + if (tab.Element("SortOrder") != null && int.TryParse(tab.Element("SortOrder").Value, out sortOrder)) + { + // Override the sort order with the imported value + contentType.PropertyGroups[caption].SortOrder = sortOrder; + } + } + } + + private void UpdateContentTypesProperties(IContentType contentType, XElement genericPropertiesElement) + { + var properties = genericPropertiesElement.Elements("GenericProperty"); + foreach (var property in properties) + { + var dataTypeDefinitionId = new Guid(property.Element("Definition").Value);//Unique Id for a DataTypeDefinition + + var dataTypeDefinition = _dataTypeService.GetDataType(dataTypeDefinitionId); + + //If no DataTypeDefinition with the guid from the xml wasn't found OR the ControlId on the DataTypeDefinition didn't match the DataType Id + //We look up a DataTypeDefinition that matches + + + //get the alias as a string for use below + var propertyEditorAlias = property.Element("Type").Value.Trim(); + + //If no DataTypeDefinition with the guid from the xml wasn't found OR the ControlId on the DataTypeDefinition didn't match the DataType Id + //We look up a DataTypeDefinition that matches + + if (dataTypeDefinition == null) + { + var dataTypeDefinitions = _dataTypeService.GetByEditorAlias(propertyEditorAlias); + if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) + { + dataTypeDefinition = dataTypeDefinitions.FirstOrDefault(); + } + } + else if (dataTypeDefinition.EditorAlias != propertyEditorAlias) + { + var dataTypeDefinitions = _dataTypeService.GetByEditorAlias(propertyEditorAlias); + if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) + { + dataTypeDefinition = dataTypeDefinitions.FirstOrDefault(); + } + } + + // For backwards compatibility, if no datatype with that ID can be found, we're letting this fail silently. + // This means that the property will not be created. + if (dataTypeDefinition == null) + { + _logger.Warn("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.", + property.Element("Name").Value, dataTypeDefinitionId, property.Element("Type").Value.Trim()); + + //convert to a label! + dataTypeDefinition = _dataTypeService.GetByEditorAlias(Constants.PropertyEditors.Aliases.NoEdit).FirstOrDefault(); + //if for some odd reason this isn't there then ignore + if (dataTypeDefinition == null) continue; + } + + var sortOrder = 0; + var sortOrderElement = property.Element("SortOrder"); + if (sortOrderElement != null) + int.TryParse(sortOrderElement.Value, out sortOrder); + var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value) + { + Name = property.Element("Name").Value, + Description = (string)property.Element("Description"), + Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false, + ValidationRegExp = (string)property.Element("Validation"), + SortOrder = sortOrder + }; + + var tab = (string)property.Element("Tab"); + if (string.IsNullOrEmpty(tab)) + { + contentType.AddPropertyType(propertyType); + } + else + { + contentType.AddPropertyType(propertyType, tab); + } + } + } + + private IContentType UpdateContentTypesStructure(IContentType contentType, XElement structureElement, IReadOnlyDictionary importedContentTypes) + { + var allowedChildren = contentType.AllowedContentTypes.ToList(); + int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0; + foreach (var element in structureElement.Elements("DocumentType")) + { + var alias = element.Value; + + var allowedChild = importedContentTypes.ContainsKey(alias) ? importedContentTypes[alias] : _contentTypeService.Get(alias); + if (allowedChild == null) + { + _logger.Warn( + "Packager: Error handling DocumentType structure. DocumentType with alias '{DoctypeAlias}' could not be found and was not added to the structure for '{DoctypeStructureAlias}'.", + alias, contentType.Alias); + continue; + } + + if (allowedChildren.Any(x => x.Id.IsValueCreated && x.Id.Value == allowedChild.Id)) continue; + + allowedChildren.Add(new ContentTypeSort(new Lazy(() => allowedChild.Id), sortOrder, allowedChild.Alias)); + sortOrder++; + } + + contentType.AllowedContentTypes = allowedChildren; + return contentType; + } + + /// + /// Used during Content import to ensure that the ContentType of a content item exists + /// + /// + /// + private IContentType FindContentTypeByAlias(string contentTypeAlias) + { + var contentType = _contentTypeService.Get(contentTypeAlias); + + if (contentType == null) + throw new Exception($"ContentType matching the passed in Alias: '{contentTypeAlias}' was null"); + + return contentType; + } + + #endregion + + #region DataTypes + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional id of the user + /// An enumrable list of generated DataTypeDefinitions + public IEnumerable ImportDataTypes(IReadOnlyCollection dataTypeElements, int userId) + { + var dataTypes = new List(); + + var importedFolders = CreateDataTypeFolderStructure(dataTypeElements); + + foreach (var dataTypeElement in dataTypeElements) + { + var dataTypeDefinitionName = dataTypeElement.AttributeValue("Name"); + + var dataTypeDefinitionId = dataTypeElement.AttributeValue("Definition"); + var databaseTypeAttribute = dataTypeElement.Attribute("DatabaseType"); + + var parentId = -1; + if (importedFolders.ContainsKey(dataTypeDefinitionName)) + parentId = importedFolders[dataTypeDefinitionName]; + + var definition = _dataTypeService.GetDataType(dataTypeDefinitionId); + //If the datatypedefinition doesn't already exist we create a new new according to the one in the package xml + if (definition == null) + { + var databaseType = databaseTypeAttribute?.Value.EnumParse(true) ?? ValueStorageType.Ntext; + + // the Id field is actually the string property editor Alias + // however, the actual editor with this alias could be installed with the package, and + // therefore not yet part of the _propertyEditors collection, so we cannot try and get + // the actual editor - going with a void editor + + var editorAlias = dataTypeElement.Attribute("Id")?.Value?.Trim(); + if (!_propertyEditors.TryGet(editorAlias, out var editor)) + editor = new VoidEditor(_logger) { Alias = editorAlias }; + + var dataType = new DataType(editor) + { + Key = dataTypeDefinitionId, + Name = dataTypeDefinitionName, + DatabaseType = databaseType, + ParentId = parentId + }; + + var configurationAttributeValue = dataTypeElement.Attribute("Configuration")?.Value; + if (!string.IsNullOrWhiteSpace(configurationAttributeValue)) + dataType.Configuration = editor.GetConfigurationEditor().FromDatabase(configurationAttributeValue); + + dataTypes.Add(dataType); + } + else + { + definition.ParentId = parentId; + _dataTypeService.Save(definition, userId); + } + } + + if (dataTypes.Count > 0) + { + _dataTypeService.Save(dataTypes, userId, true); + } + + return dataTypes; + } + + private Dictionary CreateDataTypeFolderStructure(IEnumerable datatypeElements) + { + var importedFolders = new Dictionary(); + foreach (var datatypeElement in datatypeElements) + { + var foldersAttribute = datatypeElement.Attribute("Folders"); + if (foldersAttribute != null) + { + var name = datatypeElement.Attribute("Name").Value; + var folders = foldersAttribute.Value.Split('/'); + var rootFolder = HttpUtility.UrlDecode(folders[0]); + //there will only be a single result by name for level 1 (root) containers + var current = _dataTypeService.GetContainers(rootFolder, 1).FirstOrDefault(); + + if (current == null) + { + var tryCreateFolder = _dataTypeService.CreateContainer(-1, rootFolder); + if (tryCreateFolder == false) + { + _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); + throw tryCreateFolder.Exception; + } + current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); + } + + importedFolders.Add(name, current.Id); + + for (var i = 1; i < folders.Length; i++) + { + var folderName = HttpUtility.UrlDecode(folders[i]); + current = CreateDataTypeChildFolder(folderName, current); + importedFolders[name] = current.Id; + } + } + } + + return importedFolders; + } + + private EntityContainer CreateDataTypeChildFolder(string folderName, IUmbracoEntity current) + { + var children = _entityService.GetChildren(current.Id).ToArray(); + var found = children.Any(x => x.Name.InvariantEquals(folderName)); + if (found) + { + var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id; + return _dataTypeService.GetContainer(containerId); + } + + var tryCreateFolder = _dataTypeService.CreateContainer(current.Id, folderName); + if (tryCreateFolder == false) + { + _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); + throw tryCreateFolder.Exception; + } + return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); + } + + #endregion + + #region Dictionary Items + + /// + /// Imports and saves the 'DictionaryItems' part of the package xml as a list of + /// + /// Xml to import + /// + /// An enumerable list of dictionary items + public IEnumerable ImportDictionaryItems(IEnumerable dictionaryItemElementList, int userId) + { + var languages = _localizationService.GetAllLanguages().ToList(); + return ImportDictionaryItems(dictionaryItemElementList, languages, null, userId); + } + + private IEnumerable ImportDictionaryItems(IEnumerable dictionaryItemElementList, List languages, Guid? parentId, int userId) + { + var items = new List(); + foreach (var dictionaryItemElement in dictionaryItemElementList) + items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, parentId, userId)); + + return items; + } + + private IEnumerable ImportDictionaryItem(XElement dictionaryItemElement, List languages, Guid? parentId, int userId) + { + var items = new List(); + + IDictionaryItem dictionaryItem; + var key = dictionaryItemElement.Attribute("Key").Value; + if (_localizationService.DictionaryItemExists(key)) + dictionaryItem = GetAndUpdateDictionaryItem(key, dictionaryItemElement, languages); + else + dictionaryItem = CreateNewDictionaryItem(key, dictionaryItemElement, languages, parentId); + _localizationService.Save(dictionaryItem, userId); + items.Add(dictionaryItem); + + items.AddRange(ImportDictionaryItems(dictionaryItemElement.Elements("DictionaryItem"), languages, dictionaryItem.Key, userId)); + return items; + } + + private IDictionaryItem GetAndUpdateDictionaryItem(string key, XElement dictionaryItemElement, List languages) + { + var dictionaryItem = _localizationService.GetDictionaryItemByKey(key); + var translations = dictionaryItem.Translations.ToList(); + foreach (var valueElement in dictionaryItemElement.Elements("Value").Where(v => DictionaryValueIsNew(translations, v))) + AddDictionaryTranslation(translations, valueElement, languages); + dictionaryItem.Translations = translations; + return dictionaryItem; + } + + private static DictionaryItem CreateNewDictionaryItem(string key, XElement dictionaryItemElement, List languages, Guid? parentId) + { + var dictionaryItem = parentId.HasValue ? new DictionaryItem(parentId.Value, key) : new DictionaryItem(key); + var translations = new List(); + + foreach (var valueElement in dictionaryItemElement.Elements("Value")) + AddDictionaryTranslation(translations, valueElement, languages); + + dictionaryItem.Translations = translations; + return dictionaryItem; + } + + private static bool DictionaryValueIsNew(IEnumerable translations, XElement valueElement) + { + return translations.All(t => + String.Compare(t.Language.IsoCode, valueElement.Attribute("LanguageCultureAlias").Value, + StringComparison.InvariantCultureIgnoreCase) != 0 + ); + } + + private static void AddDictionaryTranslation(ICollection translations, XElement valueElement, IEnumerable languages) + { + var languageId = valueElement.Attribute("LanguageCultureAlias").Value; + var language = languages.SingleOrDefault(l => l.IsoCode == languageId); + if (language == null) + return; + var translation = new DictionaryTranslation(language, valueElement.Value); + translations.Add(translation); + } + + #endregion + + #region Languages + + + /// + /// Imports and saves the 'Languages' part of a package xml as a list of + /// + /// Xml to import + /// Optional id of the User performing the operation + /// An enumerable list of generated languages + public IEnumerable ImportLanguages(IEnumerable languageElements, int userId) + { + var list = new List(); + foreach (var languageElement in languageElements) + { + var isoCode = languageElement.AttributeValue("CultureAlias"); + var existingLanguage = _localizationService.GetLanguageByIsoCode(isoCode); + if (existingLanguage != null) continue; + var langauge = new Language(isoCode) + { + CultureName = languageElement.AttributeValue("FriendlyName") + }; + _localizationService.Save(langauge, userId); + list.Add(langauge); + } + + return list; + } + + #endregion + + #region Macros + + /// + /// Imports and saves the 'Macros' part of a package xml as a list of + /// + /// Xml to import + /// Optional id of the User performing the operation + /// + public IEnumerable ImportMacros(IEnumerable macroElements, int userId) + { + var macros = macroElements.Select(ParseMacroElement).ToList(); + + foreach (var macro in macros) + { + var existing = _macroService.GetByAlias(macro.Alias); + if (existing != null) + macro.Id = existing.Id; + + _macroService.Save(macro, userId); + } + + return macros; + } + + private IMacro ParseMacroElement(XElement macroElement) + { + var macroName = macroElement.Element("name").Value; + var macroAlias = macroElement.Element("alias").Value; + var macroType = Enum.Parse(macroElement.Element("macroType").Value); + var macroSource = macroElement.Element("macroSource").Value; + + //Following xml elements are treated as nullable properties + var useInEditorElement = macroElement.Element("useInEditor"); + var useInEditor = false; + if (useInEditorElement != null && string.IsNullOrEmpty((string)useInEditorElement) == false) + { + useInEditor = bool.Parse(useInEditorElement.Value); + } + var cacheDurationElement = macroElement.Element("refreshRate"); + var cacheDuration = 0; + if (cacheDurationElement != null && string.IsNullOrEmpty((string)cacheDurationElement) == false) + { + cacheDuration = int.Parse(cacheDurationElement.Value); + } + var cacheByMemberElement = macroElement.Element("cacheByMember"); + var cacheByMember = false; + if (cacheByMemberElement != null && string.IsNullOrEmpty((string)cacheByMemberElement) == false) + { + cacheByMember = bool.Parse(cacheByMemberElement.Value); + } + var cacheByPageElement = macroElement.Element("cacheByPage"); + var cacheByPage = false; + if (cacheByPageElement != null && string.IsNullOrEmpty((string)cacheByPageElement) == false) + { + cacheByPage = bool.Parse(cacheByPageElement.Value); + } + var dontRenderElement = macroElement.Element("dontRender"); + var dontRender = true; + if (dontRenderElement != null && string.IsNullOrEmpty((string)dontRenderElement) == false) + { + dontRender = bool.Parse(dontRenderElement.Value); + } + + var existingMacro = _macroService.GetByAlias(macroAlias) as Macro; + var macro = existingMacro ?? new Macro(macroAlias, macroName, macroSource, macroType, + cacheByPage, cacheByMember, dontRender, useInEditor, cacheDuration); + + var properties = macroElement.Element("properties"); + if (properties != null) + { + int sortOrder = 0; + foreach (var property in properties.Elements()) + { + var propertyName = property.Attribute("name").Value; + var propertyAlias = property.Attribute("alias").Value; + var editorAlias = property.Attribute("propertyType").Value; + var sortOrderAttribute = property.Attribute("sortOrder"); + if (sortOrderAttribute != null) + { + sortOrder = int.Parse(sortOrderAttribute.Value); + } + + if (macro.Properties.Values.Any(x => string.Equals(x.Alias, propertyAlias, StringComparison.OrdinalIgnoreCase))) continue; + macro.Properties.Add(new MacroProperty(propertyAlias, propertyName, sortOrder, editorAlias)); + sortOrder++; + } + } + return macro; + } + + + + + + #endregion + + #region Stylesheets + + public IEnumerable ImportStylesheets(IEnumerable stylesheetElements, int userId) + { + var result = new List(); + + foreach (var n in stylesheetElements) + { + var stylesheetName = n.Element("Name")?.Value; + if (stylesheetName.IsNullOrWhiteSpace()) continue; + + var s = _fileService.GetStylesheetByName(stylesheetName); + if (s == null) + { + var fileName = n.Element("FileName")?.Value; + if (fileName == null) continue; + var content = n.Element("Content")?.Value; + if (content == null) continue; + + s = new Stylesheet(fileName) { Content = content }; + _fileService.SaveStylesheet(s); + } + + foreach (var prop in n.XPathSelectElements("Properties/Property")) + { + var alias = prop.Element("Alias")?.Value; + var sp = s.Properties.SingleOrDefault(p => p != null && p.Alias == alias); + var name = prop.Element("Name")?.Value; + if (sp == null) + { + sp = new StylesheetProperty(name, "#" + name.ToSafeAlias(), ""); + s.AddProperty(sp); + } + else + { + //sp.Text = name; + //Changing the name requires removing the current property and then adding another new one + if (sp.Name != name) + { + s.RemoveProperty(sp.Name); + var newProp = new StylesheetProperty(name, sp.Alias, sp.Value); + s.AddProperty(newProp); + sp = newProp; + } + } + sp.Alias = alias; + sp.Value = prop.Element("Value")?.Value; + } + _fileService.SaveStylesheet(s); + result.Add(s); + } + + return result; + } + + #endregion + + #region Templates + + public IEnumerable ImportTemplate(XElement templateElement, int userId) + { + return ImportTemplates(new[] {templateElement}, userId); + } + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional user id + /// An enumrable list of generated Templates + public IEnumerable ImportTemplates(IReadOnlyCollection templateElements, int userId) + { + var templates = new List(); + + var graph = new TopoGraph>(x => x.Key, x => x.Dependencies); + + foreach (var tempElement in templateElements) + { + var dependencies = new List(); + var elementCopy = tempElement; + //Ensure that the Master of the current template is part of the import, otherwise we ignore this dependency as part of the dependency sorting. + if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false && + templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master"))) + { + dependencies.Add((string)elementCopy.Element("Master")); + } + else if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false && + templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master")) == false) + { + _logger.Info( + "Template '{TemplateAlias}' has an invalid Master '{TemplateMaster}', so the reference has been ignored.", + (string)elementCopy.Element("Alias"), + (string)elementCopy.Element("Master")); + } + + graph.AddItem(TopoGraph.CreateNode((string)elementCopy.Element("Alias"), elementCopy, dependencies)); + } + + //Sort templates by dependencies to a potential master template + var sorted = graph.GetSortedItems(); + foreach (var item in sorted) + { + var templateElement = item.Item; + + var templateName = templateElement.Element("Name").Value; + var alias = templateElement.Element("Alias").Value; + var design = templateElement.Element("Design").Value; + var masterElement = templateElement.Element("Master"); + + var isMasterPage = IsMasterPageSyntax(design); + var path = isMasterPage ? MasterpagePath(alias) : ViewPath(alias); + + var existingTemplate = _fileService.GetTemplate(alias) as Template; + var template = existingTemplate ?? new Template(templateName, alias); + template.Content = design; + if (masterElement != null && string.IsNullOrEmpty((string)masterElement) == false) + { + template.MasterTemplateAlias = masterElement.Value; + var masterTemplate = templates.FirstOrDefault(x => x.Alias == masterElement.Value); + if (masterTemplate != null) + template.MasterTemplateId = new Lazy(() => masterTemplate.Id); + } + templates.Add(template); + } + + if (templates.Any()) + _fileService.SaveTemplate(templates, userId); + + return templates; + } + + + private bool IsMasterPageSyntax(string code) + { + return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || + code.InvariantContains(" /// Constructor /// - /// + /// /// /// + /// /// /// The relative path of the package storage folder (i.e. ~/App_Data/Packages ) /// @@ -36,13 +38,14 @@ namespace Umbraco.Core.Packaging /// /// The destination root folder to extract the package files (generally the same as applicationRoot) but can be modified for testing /// - public PackageInstallation(IPackagingService packagingService, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, + public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, string packagesFolderPath, DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) { _packageExtraction = new PackageExtraction(); - _packageFileInstallation = packageFileInstallation; - _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); + _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); + _packageDataInstallation = packageDataInstallation ?? throw new ArgumentNullException(nameof(packageDataInstallation)); _parser = parser; + _packageActionRunner = packageActionRunner; _packagesFolderPath = packagesFolderPath; _applicationRootFolder = applicationRootFolder; _packageExtractionFolder = packageExtractionFolder; @@ -61,8 +64,6 @@ namespace Umbraco.Core.Packaging return compiledPackage; } - //fixme: Should we move all of the ImportXXXX methods here instead of on the IPackagingService? we don't want to have cicurlar refs - public IEnumerable InstallPackageFiles(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); @@ -79,118 +80,77 @@ namespace Umbraco.Core.Packaging public InstallationSummary InstallPackageData(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId) { - //fixme: fill this in - throw new NotImplementedException(); + //TODO: Update the PackageDefinition! + + var installationSummary = new InstallationSummary + { + DataTypesInstalled = _packageDataInstallation.ImportDataTypes(compiledPackage.DataTypes.ToList(), userId), + LanguagesInstalled = _packageDataInstallation.ImportLanguages(compiledPackage.Languages, userId), + DictionaryItemsInstalled = _packageDataInstallation.ImportDictionaryItems(compiledPackage.DictionaryItems, userId), + MacrosInstalled = _packageDataInstallation.ImportMacros(compiledPackage.Macros, userId), + TemplatesInstalled = _packageDataInstallation.ImportTemplates(compiledPackage.Templates.ToList(), userId), + DocumentTypesInstalled = _packageDataInstallation.ImportDocumentTypes(compiledPackage.DocumentTypes, userId) + }; + + //we need a reference to the imported doc types to continue + var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x); + + installationSummary.StylesheetsInstalled = _packageDataInstallation.ImportStylesheets(compiledPackage.Stylesheets, userId); + installationSummary.ContentInstalled = _packageDataInstallation.ImportContent(compiledPackage.Documents, importedDocTypes, userId); + installationSummary.Actions = _parser.GetPackageActions(XElement.Parse(compiledPackage.Actions), compiledPackage.Name); + installationSummary.MetaData = compiledPackage; + //fixme: Verify that this will work! + installationSummary.FilesInstalled = packageDefinition.Files; + installationSummary.PackageInstalled = true; + + //make sure the definition is up to date with everything + + foreach (var x in installationSummary.DataTypesInstalled) packageDefinition.DataTypes.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.LanguagesInstalled) packageDefinition.Languages.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.DictionaryItemsInstalled) packageDefinition.DictionaryItems.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.MacrosInstalled) packageDefinition.Macros.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.TemplatesInstalled) packageDefinition.Templates.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.DocumentTypesInstalled) packageDefinition.DocumentTypes.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.StylesheetsInstalled) packageDefinition.Stylesheets.Add(x.Id.ToInvariantString()); + var contentInstalled = installationSummary.ContentInstalled.ToList(); + packageDefinition.ContentNodeId = contentInstalled.Count > 0 ? contentInstalled[0].Id.ToInvariantString() : null; + + RunPackageActions(packageDefinition, installationSummary.Actions); + + return installationSummary; } - //public InstallationSummary InstallPackage(FileInfo packageFile, int userId) - //{ - // XElement dataTypes; - // XElement languages; - // XElement dictionaryItems; - // XElement macroes; - // XElement files; - // XElement templates; - // XElement documentTypes; - // XElement styleSheets; - // XElement documentSet; - // XElement documents; - // XElement actions; - // IPackageInfo metaData; - // InstallationSummary installationSummary; + private void RunPackageActions(PackageDefinition packageDefinition, IEnumerable actions) + { + foreach (var n in actions) + { + var undo = n.Undo; + if (undo) + packageDefinition.Actions += n.XmlData.ToString(); - // try - // { - // XElement rootElement = GetConfigXmlElement(packageFile); - // PackageSupportedCheck(rootElement); - // PackageStructureSanityCheck(packageFile, rootElement); - // dataTypes = rootElement.Element(Constants.Packaging.DataTypesNodeName); - // languages = rootElement.Element(Constants.Packaging.LanguagesNodeName); - // dictionaryItems = rootElement.Element(Constants.Packaging.DictionaryItemsNodeName); - // macroes = rootElement.Element(Constants.Packaging.MacrosNodeName); - // files = rootElement.Element(Constants.Packaging.FilesNodeName); - // templates = rootElement.Element(Constants.Packaging.TemplatesNodeName); - // documentTypes = rootElement.Element(Constants.Packaging.DocumentTypesNodeName); - // styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName); - // documentSet = rootElement.Element(Constants.Packaging.DocumentSetNodeName); - // documents = rootElement.Element(Constants.Packaging.DocumentsNodeName); - // actions = rootElement.Element(Constants.Packaging.ActionsNodeName); + //Run the actions tagged only for 'install' + if (n.RunAt != ActionRunAt.Install) continue; - // metaData = GetMetaData(rootElement); - // installationSummary = new InstallationSummary {MetaData = metaData}; - // } - // catch (Exception e) - // { - // throw new Exception("Error reading " + packageFile, e); - // } - - // try - // { - // var dataTypeDefinitions = EmptyEnumerableIfNull(dataTypes) ?? InstallDataTypes(dataTypes, userId); - // installationSummary.DataTypesInstalled = dataTypeDefinitions; - - // var languagesInstalled = EmptyEnumerableIfNull(languages) ?? InstallLanguages(languages, userId); - // installationSummary.LanguagesInstalled = languagesInstalled; - - // var dictionaryInstalled = EmptyEnumerableIfNull(dictionaryItems) ?? InstallDictionaryItems(dictionaryItems); - // installationSummary.DictionaryItemsInstalled = dictionaryInstalled; - - // var macros = EmptyEnumerableIfNull(macroes) ?? InstallMacros(macroes, userId); - // installationSummary.MacrosInstalled = macros; - - // var templatesInstalled = EmptyEnumerableIfNull(templates) ?? InstallTemplats(templates, userId); - // installationSummary.TemplatesInstalled = templatesInstalled; - - // var documentTypesInstalled = EmptyEnumerableIfNull(documentTypes) ?? InstallDocumentTypes(documentTypes, userId); - // installationSummary.ContentTypesInstalled =documentTypesInstalled; - - // var stylesheetsInstalled = EmptyEnumerableIfNull(styleSheets) ?? InstallStylesheets(styleSheets); - // installationSummary.StylesheetsInstalled = stylesheetsInstalled; - - // var documentsInstalled = documents != null ? InstallDocuments(documents, userId) - // : EmptyEnumerableIfNull(documentSet) - // ?? InstallDocuments(documentSet, userId); - // installationSummary.ContentInstalled = documentsInstalled; - - // var packageActions = EmptyEnumerableIfNull(actions) ?? GetPackageActions(actions, metaData.Name); - // installationSummary.Actions = packageActions; - - // installationSummary.PackageInstalled = true; - - // return installationSummary; - // } - // catch (Exception e) - // { - // throw new Exception("Error installing package " + packageFile, e); - // } - //} + if (n.Alias.IsNullOrWhiteSpace() == false) + _packageActionRunner.RunPackageAction(packageDefinition.Name, n.Alias, n.XmlData); + } + } private FileInfo GetPackageZipFile(string packageFileName) => new FileInfo(IOHelper.MapPath(_packagesFolderPath).EnsureEndsWith('\\') + packageFileName); - private static IEnumerable EmptyEnumerableIfNull(object obj) - { - return obj == null ? Enumerable.Empty() : null; - } - private XDocument GetConfigXmlDoc(FileInfo packageFile) { - var configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFile, Constants.Packaging.PackageXmlFileName, out _); + var configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFile, "package.xml", out _); var document = XDocument.Parse(configXmlContent); if (document.Root == null || - document.Root.Name.LocalName.Equals(Constants.Packaging.UmbPackageNodeName) == false) + document.Root.Name.LocalName.Equals("umbPackage") == false) throw new FormatException("xml does not have a root node called \"umbPackage\""); return document; } - public XElement GetConfigXmlElement(FileInfo packageFile) - { - var document = GetConfigXmlDoc(packageFile); - return document.Root; - } - private void ValidatePackageFile(FileInfo packageFile, CompiledPackage package) { if (!(package.Files?.Count > 0)) return; @@ -205,8 +165,8 @@ namespace Umbraco.Core.Packaging string.Join(", ", missingFiles.Select( mf => { - var sd = sourceDestination.Single(fi => fi.packageUniqueFile == mf); - return $"source: \"{sd.packageUniqueFile}\" destination: \"{sd.appRelativePath}\""; + var (packageUniqueFile, appRelativePath) = sourceDestination.Single(fi => fi.packageUniqueFile == mf); + return $"source: \"{packageUniqueFile}\" destination: \"{appRelativePath}\""; }))); } @@ -219,143 +179,7 @@ namespace Umbraco.Core.Packaging } } - private static IEnumerable GetPackageActions(XElement actionsElement, string packageName) - { - if (actionsElement == null) { return new PackageAction[0]; } - - if (string.Equals(Constants.Packaging.ActionsNodeName, actionsElement.Name.LocalName) == false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.ActionsNodeName + "\" as root", - "actionsElement"); - } - - return actionsElement.Elements(Constants.Packaging.ActionNodeName) - .Select(elemet => - { - XAttribute aliasAttr = elemet.Attribute(Constants.Packaging.AliasNodeNameCapital); - if (aliasAttr == null) - throw new ArgumentException( - "missing \"" + Constants.Packaging.AliasNodeNameCapital + "\" atribute in alias element", - "actionsElement"); - - var packageAction = new PackageAction - { - XmlData = elemet, - Alias = aliasAttr.Value, - PackageName = packageName, - }; - - - var attr = elemet.Attribute(Constants.Packaging.RunatNodeAttribute); - - if (attr != null && Enum.TryParse(attr.Value, true, out ActionRunAt runAt)) { packageAction.RunAt = runAt; } - - attr = elemet.Attribute(Constants.Packaging.UndoNodeAttribute); - - if (attr != null && bool.TryParse(attr.Value, out var undo)) { packageAction.Undo = undo; } - - - return packageAction; - }).ToArray(); - } - - private IEnumerable InstallDocuments(XElement documentsElement, int userId = 0) - { - if ((string.Equals(Constants.Packaging.DocumentSetNodeName, documentsElement.Name.LocalName) == false) - && (string.Equals(Constants.Packaging.DocumentsNodeName, documentsElement.Name.LocalName) == false)) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.DocumentsNodeName + "\" as root", - "documentsElement"); - } - - if (string.Equals(Constants.Packaging.DocumentSetNodeName, documentsElement.Name.LocalName)) - return _packagingService.ImportContent(documentsElement, -1, userId); - - return - documentsElement.Elements(Constants.Packaging.DocumentSetNodeName) - .SelectMany(documentSetElement => _packagingService.ImportContent(documentSetElement, -1, userId)) - .ToArray(); - } - - private IEnumerable InstallStylesheets(XElement styleSheetsElement) - { - if (string.Equals(Constants.Packaging.StylesheetsNodeName, styleSheetsElement.Name.LocalName) == false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.StylesheetsNodeName + "\" as root", - "styleSheetsElement"); - } - - // TODO: Call _packagingService when import stylesheets import has been implimentet - if (styleSheetsElement.HasElements == false) { return new List(); } - - throw new NotImplementedException("The packaging service do not yes have a method for importing stylesheets"); - } - - private IEnumerable InstallDocumentTypes(XElement documentTypes, int userId = 0) - { - if (string.Equals(Constants.Packaging.DocumentTypesNodeName, documentTypes.Name.LocalName) == false) - { - if (string.Equals(Constants.Packaging.DocumentTypeNodeName, documentTypes.Name.LocalName) == false) - throw new ArgumentException( - "Must be \"" + Constants.Packaging.DocumentTypesNodeName + "\" as root", "documentTypes"); - - documentTypes = new XElement(Constants.Packaging.DocumentTypesNodeName, documentTypes); - } - - return _packagingService.ImportContentTypes(documentTypes, userId); - } - - private IEnumerable InstallTemplates(XElement templateElement, int userId = 0) - { - if (string.Equals(Constants.Packaging.TemplatesNodeName, templateElement.Name.LocalName) == false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.TemplatesNodeName + "\" as root", - "templateElement"); - } - return _packagingService.ImportTemplates(templateElement, userId); - } - - private IEnumerable InstallMacros(XElement macroElements, int userId = 0) - { - if (string.Equals(Constants.Packaging.MacrosNodeName, macroElements.Name.LocalName) == false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.MacrosNodeName + "\" as root", - "macroElements"); - } - return _packagingService.ImportMacros(macroElements, userId); - } - - private IEnumerable InstallDictionaryItems(XElement dictionaryItemsElement) - { - if (string.Equals(Constants.Packaging.DictionaryItemsNodeName, dictionaryItemsElement.Name.LocalName) == - false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.DictionaryItemsNodeName + "\" as root", - "dictionaryItemsElement"); - } - return _packagingService.ImportDictionaryItems(dictionaryItemsElement); - } - - private IEnumerable InstallLanguages(XElement languageElement, int userId = 0) - { - if (string.Equals(Constants.Packaging.LanguagesNodeName, languageElement.Name.LocalName) == false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.LanguagesNodeName + "\" as root", "languageElement"); - } - return _packagingService.ImportLanguages(languageElement, userId); - } - - private IEnumerable InstallDataTypes(XElement dataTypeElements, int userId = 0) - { - if (string.Equals(Constants.Packaging.DataTypesNodeName, dataTypeElements.Name.LocalName) == false) - { - if (string.Equals(Constants.Packaging.DataTypeNodeName, dataTypeElements.Name.LocalName) == false) - { - throw new ArgumentException("Must be \"" + Constants.Packaging.DataTypeNodeName + "\" as root", "dataTypeElements"); - } - } - return _packagingService.ImportDataTypeDefinitions(dataTypeElements, userId); - } + } } diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index fcb0c66401..8aa936c8ff 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -72,81 +72,6 @@ namespace Umbraco.Core.Services #endregion - #region Importing - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional parent Id for the content being imported - /// Optional Id of the user performing the import - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated content - IEnumerable ImportContent(XElement element, int parentId = -1, int userId = 0, bool raiseEvents = true); - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional id of the User performing the operation. Default is zero (admin) - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated ContentTypes - IEnumerable ImportContentTypes(XElement element, int userId = 0, bool raiseEvents = true); - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Boolean indicating whether or not to import the - /// Optional id of the User performing the operation. Default is zero (admin) - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated ContentTypes - IEnumerable ImportContentTypes(XElement element, bool importStructure, int userId = 0, bool raiseEvents = true); - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional id of the User performing the operation. Default is zero (admin). - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated DataTypeDefinitions - IEnumerable ImportDataTypeDefinitions(XElement element, int userId = 0, bool raiseEvents = true); - - /// - /// Imports and saves the 'DictionaryItems' part of the package xml as a list of - /// - /// Xml to import - /// Optional parameter indicating whether or not to raise events - /// An enumerable list of dictionary items - IEnumerable ImportDictionaryItems(XElement dictionaryItemElementList, bool raiseEvents = true); - - /// - /// Imports and saves the 'Languages' part of a package xml as a list of - /// - /// Xml to import - /// Optional id of the User performing the operation. Default is zero (admin) - /// Optional parameter indicating whether or not to raise events - /// An enumerable list of generated languages - IEnumerable ImportLanguages(XElement languageElementList, int userId = 0, bool raiseEvents = true); - - /// - /// Imports and saves the 'Macros' part of a package xml as a list of - /// - /// Xml to import - /// Optional id of the User performing the operation - /// Optional parameter indicating whether or not to raise events - /// - IEnumerable ImportMacros(XElement element, int userId = 0, bool raiseEvents = true); - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional id of the User performing the operation. Default is zero (admin) - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated Templates - IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true); - #endregion - /// /// This will fetch an Umbraco package file from the package repository and return the file name of the downloaded package /// diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 7c379dc2dc..ba5d30f8d7 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -31,1097 +31,25 @@ namespace Umbraco.Core.Services.Implement /// public class PackagingService : IPackagingService { - //fixme: inject when ready to use this - private readonly IPackageInstallation _packageInstallation; - private readonly ILogger _logger; - private readonly IContentService _contentService; - private readonly IContentTypeService _contentTypeService; - private readonly IMacroService _macroService; - private readonly IDataTypeService _dataTypeService; - private readonly IFileService _fileService; - private readonly ILocalizationService _localizationService; - private readonly IEntityService _entityService; - private Dictionary _importedContentTypes; + private readonly IPackageInstallation _packageInstallation; private readonly IAuditService _auditService; - private readonly PropertyEditorCollection _propertyEditors; private readonly ICreatedPackagesRepository _createdPackages; private readonly IInstalledPackagesRepository _installedPackages; private static HttpClient _httpClient; public PackagingService( - ILogger logger, - IContentService contentService, - IContentTypeService contentTypeService, - IMacroService macroService, - IDataTypeService dataTypeService, - IFileService fileService, - ILocalizationService localizationService, - IEntityService entityService, IAuditService auditService, - PropertyEditorCollection propertyEditors, ICreatedPackagesRepository createdPackages, - IInstalledPackagesRepository installedPackages) - { - _logger = logger; - _contentService = contentService; - _contentTypeService = contentTypeService; - _macroService = macroService; - _dataTypeService = dataTypeService; - _fileService = fileService; - _localizationService = localizationService; - _entityService = entityService; + IInstalledPackagesRepository installedPackages, + IPackageInstallation packageInstallation) + { _auditService = auditService; - _propertyEditors = propertyEditors; _createdPackages = createdPackages; _installedPackages = installedPackages; - _importedContentTypes = new Dictionary(); + _packageInstallation = packageInstallation; } - #region Content - - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional parent Id for the content being imported - /// Optional Id of the user performing the import - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated content - public IEnumerable ImportContent(XElement element, int parentId = -1, int userId = 0, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingContent.IsRaisedEventCancelled(new ImportEventArgs(element), this)) - return Enumerable.Empty(); - } - - var name = element.Name.LocalName; - if (name.Equals("DocumentSet")) - { - //This is a regular deep-structured import - var roots = from doc in element.Elements() - where (string)doc.Attribute("isDoc") == "" - select doc; - - var contents = ParseDocumentRootXml(roots, parentId).ToList(); - if (contents.Any()) - _contentService.Save(contents, userId); - - if (raiseEvents) - ImportedContent.RaiseEvent(new ImportEventArgs(contents, element, false), this); - return contents; - } - - var attribute = element.Attribute("isDoc"); - if (attribute != null) - { - //This is a single doc import - var elements = new List { element }; - var contents = ParseDocumentRootXml(elements, parentId).ToList(); - if (contents.Any()) - _contentService.Save(contents, userId); - - if (raiseEvents) - ImportedContent.RaiseEvent(new ImportEventArgs(contents, element, false), this); - return contents; - } - - throw new ArgumentException( - "The passed in XElement is not valid! It does not contain a root element called " + - "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); - } - - private IEnumerable ParseDocumentRootXml(IEnumerable roots, int parentId) - { - var contents = new List(); - foreach (var root in roots) - { - var contentTypeAlias = root.Name.LocalName; - - if (_importedContentTypes.ContainsKey(contentTypeAlias) == false) - { - var contentType = FindContentTypeByAlias(contentTypeAlias); - _importedContentTypes.Add(contentTypeAlias, contentType); - } - - var content = CreateContentFromXml(root, _importedContentTypes[contentTypeAlias], null, parentId); - contents.Add(content); - - var children = (from child in root.Elements() - where (string)child.Attribute("isDoc") == "" - select child) - .ToList(); - if (children.Any()) - contents.AddRange(CreateContentFromXml(children, content)); - } - return contents; - } - - private IEnumerable CreateContentFromXml(IEnumerable children, IContent parent) - { - var list = new List(); - foreach (var child in children) - { - string contentTypeAlias = child.Name.LocalName; - - if (_importedContentTypes.ContainsKey(contentTypeAlias) == false) - { - var contentType = FindContentTypeByAlias(contentTypeAlias); - _importedContentTypes.Add(contentTypeAlias, contentType); - } - - //Create and add the child to the list - var content = CreateContentFromXml(child, _importedContentTypes[contentTypeAlias], parent, default(int)); - list.Add(content); - - //Recursive call - XElement child1 = child; - var grandChildren = (from grand in child1.Elements() - where (string) grand.Attribute("isDoc") == "" - select grand).ToList(); - - if (grandChildren.Any()) - list.AddRange(CreateContentFromXml(grandChildren, content)); - } - - return list; - } - - private IContent CreateContentFromXml(XElement element, IContentType contentType, IContent parent, int parentId) - { - var id = element.Attribute("id").Value; - var level = element.Attribute("level").Value; - var sortOrder = element.Attribute("sortOrder").Value; - var nodeName = element.Attribute("nodeName").Value; - var path = element.Attribute("path").Value; - //TODO: Shouldn't we be using this value??? - var template = element.Attribute("template").Value; - var key = Guid.Empty; - - var properties = from property in element.Elements() - where property.Attribute("isDoc") == null - select property; - - IContent content = parent == null - ? new Content(nodeName, parentId, contentType) - { - Level = int.Parse(level), - SortOrder = int.Parse(sortOrder) - } - : new Content(nodeName, parent, contentType) - { - Level = int.Parse(level), - SortOrder = int.Parse(sortOrder) - }; - - if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key)) - { - // update the Guid (for UDI support) - content.Key = key; - } - - foreach (var property in properties) - { - string propertyTypeAlias = property.Name.LocalName; - if (content.HasProperty(propertyTypeAlias)) - { - var propertyValue = property.Value; - - var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias); - - //set property value - content.SetValue(propertyTypeAlias, propertyValue); - } - } - - return content; - } - - #endregion - - #region ContentTypes - - - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional id of the User performing the operation. Default is zero (admin). - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated ContentTypes - public IEnumerable ImportContentTypes(XElement element, int userId = 0, bool raiseEvents = true) - { - return ImportContentTypes(element, true, userId); - } - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Boolean indicating whether or not to import the - /// Optional id of the User performing the operation. Default is zero (admin). - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated ContentTypes - public IEnumerable ImportContentTypes(XElement element, bool importStructure, int userId = 0, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingContentType.IsRaisedEventCancelled(new ImportEventArgs(element), this)) - return Enumerable.Empty(); - } - - var name = element.Name.LocalName; - if (name.Equals("DocumentTypes") == false && name.Equals("DocumentType") == false) - { - throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'DocumentTypes' for multiple imports or 'DocumentType' for a single import."); - } - - _importedContentTypes = new Dictionary(); - var unsortedDocumentTypes = name.Equals("DocumentTypes") - ? (from doc in element.Elements("DocumentType") select doc).ToList() - : new List { element }; - - //When you are importing a single doc type we have to assume that the depedencies are already there. - //Otherwise something like uSync won't work. - var graph = new TopoGraph>(x => x.Key, x => x.Dependencies); - var isSingleDocTypeImport = unsortedDocumentTypes.Count == 1; - - var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes); - - if (isSingleDocTypeImport == false) - { - //NOTE Here we sort the doctype XElements based on dependencies - //before creating the doc types - this should also allow for a better structure/inheritance support. - foreach (var documentType in unsortedDocumentTypes) - { - var elementCopy = documentType; - var infoElement = elementCopy.Element("Info"); - var dependencies = new HashSet(); - - //Add the Master as a dependency - if (string.IsNullOrEmpty((string)infoElement.Element("Master")) == false) - { - dependencies.Add(infoElement.Element("Master").Value); - } - - //Add compositions as dependencies - var compositionsElement = infoElement.Element("Compositions"); - if (compositionsElement != null && compositionsElement.HasElements) - { - var compositions = compositionsElement.Elements("Composition"); - if (compositions.Any()) - { - foreach (var composition in compositions) - { - dependencies.Add(composition.Value); - } - } - } - - graph.AddItem(TopoGraph.CreateNode(infoElement.Element("Alias").Value, elementCopy, dependencies.ToArray())); - } - } - - //Sorting the Document Types based on dependencies - if its not a single doc type import ref. #U4-5921 - var documentTypes = isSingleDocTypeImport - ? unsortedDocumentTypes.ToList() - : graph.GetSortedItems().Select(x => x.Item).ToList(); - - //Iterate the sorted document types and create them as IContentType objects - foreach (var documentType in documentTypes) - { - var alias = documentType.Element("Info").Element("Alias").Value; - if (_importedContentTypes.ContainsKey(alias) == false) - { - var contentType = _contentTypeService.Get(alias); - _importedContentTypes.Add(alias, contentType == null - ? CreateContentTypeFromXml(documentType) - : UpdateContentTypeFromXml(documentType, contentType)); - } - } - - foreach (var contentType in _importedContentTypes) - { - var ct = contentType.Value; - if (importedFolders.ContainsKey(ct.Alias)) - { - ct.ParentId = importedFolders[ct.Alias]; - } - } - - //Save the newly created/updated IContentType objects - var list = _importedContentTypes.Select(x => x.Value).ToList(); - _contentTypeService.Save(list, userId); - - //Now we can finish the import by updating the 'structure', - //which requires the doc types to be saved/available in the db - if (importStructure) - { - var updatedContentTypes = new List(); - //Update the structure here - we can't do it untill all DocTypes have been created - foreach (var documentType in documentTypes) - { - var alias = documentType.Element("Info").Element("Alias").Value; - var structureElement = documentType.Element("Structure"); - //Ensure that we only update ContentTypes which has actual structure-elements - if (structureElement == null || structureElement.Elements("DocumentType").Any() == false) continue; - - var updated = UpdateContentTypesStructure(_importedContentTypes[alias], structureElement); - updatedContentTypes.Add(updated); - } - //Update ContentTypes with a newly added structure/list of allowed children - if (updatedContentTypes.Any()) - _contentTypeService.Save(updatedContentTypes, userId); - } - - if (raiseEvents) - ImportedContentType.RaiseEvent(new ImportEventArgs(list, element, false), this); - - return list; - } - - private Dictionary CreateContentTypeFolderStructure(IEnumerable unsortedDocumentTypes) - { - var importedFolders = new Dictionary(); - foreach (var documentType in unsortedDocumentTypes) - { - var foldersAttribute = documentType.Attribute("Folders"); - var infoElement = documentType.Element("Info"); - if (foldersAttribute != null && infoElement != null - //don't import any folder if this is a child doc type - the parent doc type will need to - //exist which contains it's folders - && ((string)infoElement.Element("Master")).IsNullOrWhiteSpace()) - { - var alias = documentType.Element("Info").Element("Alias").Value; - var folders = foldersAttribute.Value.Split('/'); - var rootFolder = HttpUtility.UrlDecode(folders[0]); - //level 1 = root level folders, there can only be one with the same name - var current = _contentTypeService.GetContainers(rootFolder, 1).FirstOrDefault(); - - if (current == null) - { - var tryCreateFolder = _contentTypeService.CreateContainer(-1, rootFolder); - if (tryCreateFolder == false) - { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); - throw tryCreateFolder.Exception; - } - var rootFolderId = tryCreateFolder.Result.Entity.Id; - current = _contentTypeService.GetContainer(rootFolderId); - } - - importedFolders.Add(alias, current.Id); - - for (var i = 1; i < folders.Length; i++) - { - var folderName = HttpUtility.UrlDecode(folders[i]); - current = CreateContentTypeChildFolder(folderName, current); - importedFolders[alias] = current.Id; - } - } - } - - return importedFolders; - } - - private EntityContainer CreateContentTypeChildFolder(string folderName, IUmbracoEntity current) - { - var children = _entityService.GetChildren(current.Id).ToArray(); - var found = children.Any(x => x.Name.InvariantEquals(folderName)); - if (found) - { - var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id; - return _contentTypeService.GetContainer(containerId); - } - - var tryCreateFolder = _contentTypeService.CreateContainer(current.Id, folderName); - if (tryCreateFolder == false) - { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); - throw tryCreateFolder.Exception; - } - return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); - } - - private IContentType CreateContentTypeFromXml(XElement documentType) - { - var infoElement = documentType.Element("Info"); - - //Name of the master corresponds to the parent - var masterElement = infoElement.Element("Master"); - IContentType parent = null; - if (masterElement != null) - { - var masterAlias = masterElement.Value; - parent = _importedContentTypes.ContainsKey(masterAlias) - ? _importedContentTypes[masterAlias] - : _contentTypeService.Get(masterAlias); - } - - var alias = infoElement.Element("Alias").Value; - var contentType = parent == null - ? new ContentType(-1) { Alias = alias } - : new ContentType(parent, alias); - - if (parent != null) - contentType.AddContentType(parent); - - return UpdateContentTypeFromXml(documentType, contentType); - } - - private IContentType UpdateContentTypeFromXml(XElement documentType, IContentType contentType) - { - var infoElement = documentType.Element("Info"); - var defaultTemplateElement = infoElement.Element("DefaultTemplate"); - - contentType.Name = infoElement.Element("Name").Value; - contentType.Icon = infoElement.Element("Icon").Value; - contentType.Thumbnail = infoElement.Element("Thumbnail").Value; - contentType.Description = infoElement.Element("Description").Value; - - //NOTE AllowAtRoot is a new property in the package xml so we need to verify it exists before using it. - var allowAtRoot = infoElement.Element("AllowAtRoot"); - if (allowAtRoot != null) - contentType.AllowedAsRoot = allowAtRoot.Value.InvariantEquals("true"); - - //NOTE IsListView is a new property in the package xml so we need to verify it exists before using it. - var isListView = infoElement.Element("IsListView"); - if (isListView != null) - contentType.IsContainer = isListView.Value.InvariantEquals("true"); - - //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set - var masterElement = infoElement.Element("Master"); - if (masterElement != null) - { - var masterAlias = masterElement.Value; - IContentType parent = _importedContentTypes.ContainsKey(masterAlias) - ? _importedContentTypes[masterAlias] - : _contentTypeService.Get(masterAlias); - - contentType.SetParent(parent); - } - - //Update Compositions on the ContentType to ensure that they are as is defined in the package xml - var compositionsElement = infoElement.Element("Compositions"); - if (compositionsElement != null && compositionsElement.HasElements) - { - var compositions = compositionsElement.Elements("Composition"); - if (compositions.Any()) - { - foreach (var composition in compositions) - { - var compositionAlias = composition.Value; - var compositionContentType = _importedContentTypes.ContainsKey(compositionAlias) - ? _importedContentTypes[compositionAlias] - : _contentTypeService.Get(compositionAlias); - var added = contentType.AddContentType(compositionContentType); - } - } - } - - UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement); - UpdateContentTypesTabs(contentType, documentType.Element("Tabs")); - UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties")); - - return contentType; - } - - private void UpdateContentTypesAllowedTemplates(IContentType contentType, - XElement allowedTemplatesElement, XElement defaultTemplateElement) - { - if (allowedTemplatesElement != null && allowedTemplatesElement.Elements("Template").Any()) - { - var allowedTemplates = contentType.AllowedTemplates.ToList(); - foreach (var templateElement in allowedTemplatesElement.Elements("Template")) - { - var alias = templateElement.Value; - var template = _fileService.GetTemplate(alias.ToSafeAlias()); - if (template != null) - { - if (allowedTemplates.Any(x => x.Id == template.Id)) continue; - allowedTemplates.Add(template); - } - else - { - _logger.Warn("Packager: Error handling allowed templates. Template with alias '{TemplateAlias}' could not be found.", alias); - } - } - - contentType.AllowedTemplates = allowedTemplates; - } - - if (string.IsNullOrEmpty((string)defaultTemplateElement) == false) - { - var defaultTemplate = _fileService.GetTemplate(defaultTemplateElement.Value.ToSafeAlias()); - if (defaultTemplate != null) - { - contentType.SetDefaultTemplate(defaultTemplate); - } - else - { - _logger.Warn("Packager: Error handling default template. Default template with alias '{DefaultTemplateAlias}' could not be found.", defaultTemplateElement.Value); - } - } - } - - private void UpdateContentTypesTabs(IContentType contentType, XElement tabElement) - { - if (tabElement == null) - return; - - var tabs = tabElement.Elements("Tab"); - foreach (var tab in tabs) - { - var id = tab.Element("Id").Value;//Do we need to use this for tracking? - var caption = tab.Element("Caption").Value; - - if (contentType.PropertyGroups.Contains(caption) == false) - { - contentType.AddPropertyGroup(caption); - - } - - int sortOrder; - if (tab.Element("SortOrder") != null && int.TryParse(tab.Element("SortOrder").Value, out sortOrder)) - { - // Override the sort order with the imported value - contentType.PropertyGroups[caption].SortOrder = sortOrder; - } - } - } - - private void UpdateContentTypesProperties(IContentType contentType, XElement genericPropertiesElement) - { - var properties = genericPropertiesElement.Elements("GenericProperty"); - foreach (var property in properties) - { - var dataTypeDefinitionId = new Guid(property.Element("Definition").Value);//Unique Id for a DataTypeDefinition - - var dataTypeDefinition = _dataTypeService.GetDataType(dataTypeDefinitionId); - - //If no DataTypeDefinition with the guid from the xml wasn't found OR the ControlId on the DataTypeDefinition didn't match the DataType Id - //We look up a DataTypeDefinition that matches - - - //get the alias as a string for use below - var propertyEditorAlias = property.Element("Type").Value.Trim(); - - //If no DataTypeDefinition with the guid from the xml wasn't found OR the ControlId on the DataTypeDefinition didn't match the DataType Id - //We look up a DataTypeDefinition that matches - - if (dataTypeDefinition == null) - { - var dataTypeDefinitions = _dataTypeService.GetByEditorAlias(propertyEditorAlias); - if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) - { - dataTypeDefinition = dataTypeDefinitions.FirstOrDefault(); - } - } - else if (dataTypeDefinition.EditorAlias != propertyEditorAlias) - { - var dataTypeDefinitions = _dataTypeService.GetByEditorAlias(propertyEditorAlias); - if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) - { - dataTypeDefinition = dataTypeDefinitions.FirstOrDefault(); - } - } - - // For backwards compatibility, if no datatype with that ID can be found, we're letting this fail silently. - // This means that the property will not be created. - if (dataTypeDefinition == null) - { - _logger.Warn("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.", - property.Element("Name").Value, dataTypeDefinitionId, property.Element("Type").Value.Trim()); - - //convert to a label! - dataTypeDefinition = _dataTypeService.GetByEditorAlias(Constants.PropertyEditors.Aliases.NoEdit).FirstOrDefault(); - //if for some odd reason this isn't there then ignore - if (dataTypeDefinition == null) continue; - } - - var sortOrder = 0; - var sortOrderElement = property.Element("SortOrder"); - if (sortOrderElement != null) - int.TryParse(sortOrderElement.Value, out sortOrder); - var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value) - { - Name = property.Element("Name").Value, - Description = (string)property.Element("Description"), - Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false, - ValidationRegExp = (string)property.Element("Validation"), - SortOrder = sortOrder - }; - - var tab = (string)property.Element("Tab"); - if (string.IsNullOrEmpty(tab)) - { - contentType.AddPropertyType(propertyType); - } - else - { - contentType.AddPropertyType(propertyType, tab); - } - } - } - - private IContentType UpdateContentTypesStructure(IContentType contentType, XElement structureElement) - { - var allowedChildren = contentType.AllowedContentTypes.ToList(); - int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0; - foreach (var element in structureElement.Elements("DocumentType")) - { - var alias = element.Value; - - var allowedChild = _importedContentTypes.ContainsKey(alias) ? _importedContentTypes[alias] : _contentTypeService.Get(alias); - if (allowedChild == null) - { - _logger.Warn( - "Packager: Error handling DocumentType structure. DocumentType with alias '{DoctypeAlias}' could not be found and was not added to the structure for '{DoctypeStructureAlias}'.", - alias, contentType.Alias); - continue; - } - - if (allowedChildren.Any(x => x.Id.IsValueCreated && x.Id.Value == allowedChild.Id)) continue; - - allowedChildren.Add(new ContentTypeSort(new Lazy(() => allowedChild.Id), sortOrder, allowedChild.Alias)); - sortOrder++; - } - - contentType.AllowedContentTypes = allowedChildren; - return contentType; - } - - /// - /// Used during Content import to ensure that the ContentType of a content item exists - /// - /// - /// - private IContentType FindContentTypeByAlias(string contentTypeAlias) - { - var contentType = _contentTypeService.Get(contentTypeAlias); - - if (contentType == null) - throw new Exception($"ContentType matching the passed in Alias: '{contentTypeAlias}' was null"); - - return contentType; - } - - #endregion - - #region DataTypes - - - - - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional id of the user - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated DataTypeDefinitions - public IEnumerable ImportDataTypeDefinitions(XElement element, int userId = 0, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingDataType.IsRaisedEventCancelled(new ImportEventArgs(element), this)) - return Enumerable.Empty(); - } - - var name = element.Name.LocalName; - if (name.Equals("DataTypes") == false && name.Equals("DataType") == false) - { - throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'DataTypes' for multiple imports or 'DataType' for a single import."); - } - - var dataTypes = new List(); - var dataTypeElements = name.Equals("DataTypes") - ? (from doc in element.Elements("DataType") select doc).ToList() - : new List { element }; - - var importedFolders = CreateDataTypeFolderStructure(dataTypeElements); - - foreach (var dataTypeElement in dataTypeElements) - { - var dataTypeDefinitionName = dataTypeElement.Attribute("Name").Value; - - var dataTypeDefinitionId = new Guid(dataTypeElement.Attribute("Definition").Value); - var databaseTypeAttribute = dataTypeElement.Attribute("DatabaseType"); - - var parentId = -1; - if (importedFolders.ContainsKey(dataTypeDefinitionName)) - parentId = importedFolders[dataTypeDefinitionName]; - - var definition = _dataTypeService.GetDataType(dataTypeDefinitionId); - //If the datatypedefinition doesn't already exist we create a new new according to the one in the package xml - if (definition == null) - { - var databaseType = databaseTypeAttribute != null - ? databaseTypeAttribute.Value.EnumParse(true) - : ValueStorageType.Ntext; - - // the Id field is actually the string property editor Alias - // however, the actual editor with this alias could be installed with the package, and - // therefore not yet part of the _propertyEditors collection, so we cannot try and get - // the actual editor - going with a void editor - - var editorAlias = dataTypeElement.Attribute("Id")?.Value?.Trim(); - if (!_propertyEditors.TryGet(editorAlias, out var editor)) - editor = new VoidEditor(_logger) { Alias = editorAlias }; - - var dataType = new DataType(editor) - { - Key = dataTypeDefinitionId, - Name = dataTypeDefinitionName, - DatabaseType = databaseType, - ParentId = parentId - }; - - var configurationAttributeValue = dataTypeElement.Attribute("Configuration")?.Value; - if (!string.IsNullOrWhiteSpace(configurationAttributeValue)) - dataType.Configuration = editor.GetConfigurationEditor().FromDatabase(configurationAttributeValue); - - dataTypes.Add(dataType); - } - else - { - definition.ParentId = parentId; - _dataTypeService.Save(definition, userId); - } - } - - if (dataTypes.Count > 0) - { - _dataTypeService.Save(dataTypes, userId, true); - } - - if (raiseEvents) - ImportedDataType.RaiseEvent(new ImportEventArgs(dataTypes, element, false), this); - - return dataTypes; - } - - private Dictionary CreateDataTypeFolderStructure(IEnumerable datatypeElements) - { - var importedFolders = new Dictionary(); - foreach (var datatypeElement in datatypeElements) - { - var foldersAttribute = datatypeElement.Attribute("Folders"); - if (foldersAttribute != null) - { - var name = datatypeElement.Attribute("Name").Value; - var folders = foldersAttribute.Value.Split('/'); - var rootFolder = HttpUtility.UrlDecode(folders[0]); - //there will only be a single result by name for level 1 (root) containers - var current = _dataTypeService.GetContainers(rootFolder, 1).FirstOrDefault(); - - if (current == null) - { - var tryCreateFolder = _dataTypeService.CreateContainer(-1, rootFolder); - if (tryCreateFolder == false) - { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); - throw tryCreateFolder.Exception; - } - current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); - } - - importedFolders.Add(name, current.Id); - - for (var i = 1; i < folders.Length; i++) - { - var folderName = HttpUtility.UrlDecode(folders[i]); - current = CreateDataTypeChildFolder(folderName, current); - importedFolders[name] = current.Id; - } - } - } - - return importedFolders; - } - - private EntityContainer CreateDataTypeChildFolder(string folderName, IUmbracoEntity current) - { - var children = _entityService.GetChildren(current.Id).ToArray(); - var found = children.Any(x => x.Name.InvariantEquals(folderName)); - if (found) - { - var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id; - return _dataTypeService.GetContainer(containerId); - } - - var tryCreateFolder = _dataTypeService.CreateContainer(current.Id, folderName); - if (tryCreateFolder == false) - { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); - throw tryCreateFolder.Exception; - } - return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); - } - - #endregion - - #region Dictionary Items - - - - - - /// - /// Imports and saves the 'DictionaryItems' part of the package xml as a list of - /// - /// Xml to import - /// Optional parameter indicating whether or not to raise events - /// An enumerable list of dictionary items - public IEnumerable ImportDictionaryItems(XElement dictionaryItemElementList, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingDictionaryItem.IsRaisedEventCancelled(new ImportEventArgs(dictionaryItemElementList), this)) - return Enumerable.Empty(); - } - - var languages = _localizationService.GetAllLanguages().ToList(); - return ImportDictionaryItems(dictionaryItemElementList, languages, raiseEvents); - } - - private IEnumerable ImportDictionaryItems(XElement dictionaryItemElementList, List languages, bool raiseEvents, Guid? parentId = null) - { - var items = new List(); - foreach (var dictionaryItemElement in dictionaryItemElementList.Elements("DictionaryItem")) - items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, raiseEvents, parentId)); - - - if (raiseEvents) - ImportedDictionaryItem.RaiseEvent(new ImportEventArgs(items, dictionaryItemElementList, false), this); - - return items; - } - - private IEnumerable ImportDictionaryItem(XElement dictionaryItemElement, List languages, bool raiseEvents, Guid? parentId) - { - var items = new List(); - - IDictionaryItem dictionaryItem; - var key = dictionaryItemElement.Attribute("Key").Value; - if (_localizationService.DictionaryItemExists(key)) - dictionaryItem = GetAndUpdateDictionaryItem(key, dictionaryItemElement, languages); - else - dictionaryItem = CreateNewDictionaryItem(key, dictionaryItemElement, languages, parentId); - _localizationService.Save(dictionaryItem); - items.Add(dictionaryItem); - - items.AddRange(ImportDictionaryItems(dictionaryItemElement, languages, raiseEvents, dictionaryItem.Key)); - return items; - } - - private IDictionaryItem GetAndUpdateDictionaryItem(string key, XElement dictionaryItemElement, List languages) - { - var dictionaryItem = _localizationService.GetDictionaryItemByKey(key); - var translations = dictionaryItem.Translations.ToList(); - foreach (var valueElement in dictionaryItemElement.Elements("Value").Where(v => DictionaryValueIsNew(translations, v))) - AddDictionaryTranslation(translations, valueElement, languages); - dictionaryItem.Translations = translations; - return dictionaryItem; - } - - private static DictionaryItem CreateNewDictionaryItem(string key, XElement dictionaryItemElement, List languages, Guid? parentId) - { - var dictionaryItem = parentId.HasValue ? new DictionaryItem(parentId.Value, key) : new DictionaryItem(key); - var translations = new List(); - - foreach (var valueElement in dictionaryItemElement.Elements("Value")) - AddDictionaryTranslation(translations, valueElement, languages); - - dictionaryItem.Translations = translations; - return dictionaryItem; - } - - private static bool DictionaryValueIsNew(IEnumerable translations, XElement valueElement) - { - return translations.All(t => - String.Compare(t.Language.IsoCode, valueElement.Attribute("LanguageCultureAlias").Value, - StringComparison.InvariantCultureIgnoreCase) != 0 - ); - } - - private static void AddDictionaryTranslation(ICollection translations, XElement valueElement, IEnumerable languages) - { - var languageId = valueElement.Attribute("LanguageCultureAlias").Value; - var language = languages.SingleOrDefault(l => l.IsoCode == languageId); - if (language == null) - return; - var translation = new DictionaryTranslation(language, valueElement.Value); - translations.Add(translation); - } - - #endregion - - #region Languages - - - - - - /// - /// Imports and saves the 'Languages' part of a package xml as a list of - /// - /// Xml to import - /// Optional id of the User performing the operation - /// Optional parameter indicating whether or not to raise events - /// An enumerable list of generated languages - public IEnumerable ImportLanguages(XElement languageElementList, int userId = 0, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingLanguage.IsRaisedEventCancelled(new ImportEventArgs(languageElementList), this)) - return Enumerable.Empty(); - } - - var list = new List(); - foreach (var languageElement in languageElementList.Elements("Language")) - { - var isoCode = languageElement.Attribute("CultureAlias").Value; - var existingLanguage = _localizationService.GetLanguageByIsoCode(isoCode); - if (existingLanguage == null) - { - var langauge = new Language(isoCode) - { - CultureName = languageElement.Attribute("FriendlyName").Value - }; - _localizationService.Save(langauge); - list.Add(langauge); - } - } - - if (raiseEvents) - ImportedLanguage.RaiseEvent(new ImportEventArgs(list, languageElementList, false), this); - - return list; - } - - #endregion - - #region Macros - - /// - /// Imports and saves the 'Macros' part of a package xml as a list of - /// - /// Xml to import - /// Optional id of the User performing the operation - /// Optional parameter indicating whether or not to raise events - /// - public IEnumerable ImportMacros(XElement element, int userId = 0, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingMacro.IsRaisedEventCancelled(new ImportEventArgs(element), this)) - return Enumerable.Empty(); - } - - var name = element.Name.LocalName; - if (name.Equals("Macros") == false && name.Equals("macro") == false) - { - throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'Macros' for multiple imports or 'macro' for a single import."); - } - - var macroElements = name.Equals("Macros") - ? (from doc in element.Elements("macro") select doc).ToList() - : new List { element }; - - var macros = macroElements.Select(ParseMacroElement).ToList(); - - foreach (var macro in macros) - { - var existing = _macroService.GetByAlias(macro.Alias); - if (existing != null) - macro.Id = existing.Id; - - _macroService.Save(macro, userId); - } - - if (raiseEvents) - ImportedMacro.RaiseEvent(new ImportEventArgs(macros, element, false), this); - - return macros; - } - - private IMacro ParseMacroElement(XElement macroElement) - { - var macroName = macroElement.Element("name").Value; - var macroAlias = macroElement.Element("alias").Value; - var macroType = Enum.Parse(macroElement.Element("macroType").Value); - var macroSource = macroElement.Element("macroSource").Value; - - //Following xml elements are treated as nullable properties - var useInEditorElement = macroElement.Element("useInEditor"); - var useInEditor = false; - if (useInEditorElement != null && string.IsNullOrEmpty((string)useInEditorElement) == false) - { - useInEditor = bool.Parse(useInEditorElement.Value); - } - var cacheDurationElement = macroElement.Element("refreshRate"); - var cacheDuration = 0; - if (cacheDurationElement != null && string.IsNullOrEmpty((string)cacheDurationElement) == false) - { - cacheDuration = int.Parse(cacheDurationElement.Value); - } - var cacheByMemberElement = macroElement.Element("cacheByMember"); - var cacheByMember = false; - if (cacheByMemberElement != null && string.IsNullOrEmpty((string)cacheByMemberElement) == false) - { - cacheByMember = bool.Parse(cacheByMemberElement.Value); - } - var cacheByPageElement = macroElement.Element("cacheByPage"); - var cacheByPage = false; - if (cacheByPageElement != null && string.IsNullOrEmpty((string)cacheByPageElement) == false) - { - cacheByPage = bool.Parse(cacheByPageElement.Value); - } - var dontRenderElement = macroElement.Element("dontRender"); - var dontRender = true; - if (dontRenderElement != null && string.IsNullOrEmpty((string)dontRenderElement) == false) - { - dontRender = bool.Parse(dontRenderElement.Value); - } - - var existingMacro = _macroService.GetByAlias(macroAlias) as Macro; - var macro = existingMacro ?? new Macro(macroAlias, macroName, macroSource, macroType, - cacheByPage, cacheByMember, dontRender, useInEditor, cacheDuration); - - var properties = macroElement.Element("properties"); - if (properties != null) - { - int sortOrder = 0; - foreach (var property in properties.Elements()) - { - var propertyName = property.Attribute("name").Value; - var propertyAlias = property.Attribute("alias").Value; - var editorAlias = property.Attribute("propertyType").Value; - var sortOrderAttribute = property.Attribute("sortOrder"); - if (sortOrderAttribute != null) - { - sortOrder = int.Parse(sortOrderAttribute.Value); - } - - if (macro.Properties.Values.Any(x => string.Equals(x.Alias, propertyAlias, StringComparison.OrdinalIgnoreCase))) continue; - macro.Properties.Add(new MacroProperty(propertyAlias, propertyName, sortOrder, editorAlias)); - sortOrder++; - } - } - return macro; - } - - - - - - #endregion - #region Package Files /// @@ -1167,139 +95,6 @@ namespace Umbraco.Core.Services.Implement #endregion - #region Templates - - /// - /// Imports and saves package xml as - /// - /// Xml to import - /// Optional user id - /// Optional parameter indicating whether or not to raise events - /// An enumrable list of generated Templates - public IEnumerable ImportTemplates(XElement element, int userId = 0, bool raiseEvents = true) - { - if (raiseEvents) - { - if (ImportingTemplate.IsRaisedEventCancelled(new ImportEventArgs(element), this)) - return Enumerable.Empty(); - } - - var name = element.Name.LocalName; - if (name.Equals("Templates") == false && name.Equals("Template") == false) - { - throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'Templates' for multiple imports or 'Template' for a single import."); - } - - var templates = new List(); - var templateElements = name.Equals("Templates") - ? (from doc in element.Elements("Template") select doc).ToList() - : new List { element }; - - var graph = new TopoGraph>(x => x.Key, x => x.Dependencies); - - foreach (XElement tempElement in templateElements) - { - var dependencies = new List(); - var elementCopy = tempElement; - //Ensure that the Master of the current template is part of the import, otherwise we ignore this dependency as part of the dependency sorting. - if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false && - templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master"))) - { - dependencies.Add((string)elementCopy.Element("Master")); - } - else if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false && - templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master")) == false) - { - _logger.Info( - "Template '{TemplateAlias}' has an invalid Master '{TemplateMaster}', so the reference has been ignored.", - (string) elementCopy.Element("Alias"), - (string) elementCopy.Element("Master")); - } - - graph.AddItem(TopoGraph.CreateNode((string) elementCopy.Element("Alias"), elementCopy, dependencies)); - } - - //Sort templates by dependencies to a potential master template - var sorted = graph.GetSortedItems(); - foreach (var item in sorted) - { - var templateElement = item.Item; - - var templateName = templateElement.Element("Name").Value; - var alias = templateElement.Element("Alias").Value; - var design = templateElement.Element("Design").Value; - var masterElement = templateElement.Element("Master"); - - var isMasterPage = IsMasterPageSyntax(design); - var path = isMasterPage ? MasterpagePath(alias) : ViewPath(alias); - - var existingTemplate = _fileService.GetTemplate(alias) as Template; - var template = existingTemplate ?? new Template(templateName, alias); - template.Content = design; - if (masterElement != null && string.IsNullOrEmpty((string)masterElement) == false) - { - template.MasterTemplateAlias = masterElement.Value; - var masterTemplate = templates.FirstOrDefault(x => x.Alias == masterElement.Value); - if (masterTemplate != null) - template.MasterTemplateId = new Lazy(() => masterTemplate.Id); - } - templates.Add(template); - } - - if (templates.Any()) - _fileService.SaveTemplate(templates, userId); - - if (raiseEvents) - ImportedTemplate.RaiseEvent(new ImportEventArgs(templates, element, false), this); - - return templates; - } - - - private bool IsMasterPageSyntax(string code) - { - return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || - code.InvariantContains(" ImportStylesheets(XElement element, int userId = 0, bool raiseEvents = true) - { - - if (raiseEvents) - { - if (ImportingStylesheets.IsRaisedEventCancelled(new ImportEventArgs(element), this)) - return Enumerable.Empty(); - } - - IEnumerable styleSheets = Enumerable.Empty(); - - if (element.Elements().Any()) - throw new NotImplementedException("This needs to be implimentet"); - - - if (raiseEvents) - ImportingStylesheets.RaiseEvent(new ImportEventArgs(styleSheets, element, false), this); - - return styleSheets; - - } - - #endregion - #region Installation public CompiledPackage GetCompiledPackageInfo(string packageFileName) => _packageInstallation.ReadPackage(packageFileName); @@ -1317,8 +112,7 @@ namespace Umbraco.Core.Services.Implement SaveInstalledPackage(packageDefinition); - if (userId > -1) - _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package files installed for package '{compiledPackage.Name}'."); + _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package files installed for package '{compiledPackage.Name}'."); return files; } @@ -1337,6 +131,8 @@ namespace Umbraco.Core.Services.Implement var summary = _packageInstallation.InstallPackageData(packageDefinition, compiledPackage, userId); + SaveInstalledPackage(packageDefinition); + _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package data installed for package '{compiledPackage.Name}'."); ImportedPackage.RaiseEvent(new ImportPackageEventArgs(summary, compiledPackage, false), this); @@ -1383,15 +179,6 @@ namespace Umbraco.Core.Services.Implement #endregion - /// - /// This method can be used to trigger the 'ImportedPackage' event when a package is installed by something else but this service. - /// - /// - internal static void OnImportedPackage(ImportPackageEventArgs args) - { - ImportedPackage.RaiseEvent(args, null); - } - /// /// This method can be used to trigger the 'UninstalledPackage' event when a package is uninstalled by something else but this service. /// @@ -1402,80 +189,6 @@ namespace Umbraco.Core.Services.Implement } #region Event Handlers - /// - /// Occurs before Importing Content - /// - public static event TypedEventHandler> ImportingContent; - - /// - /// Occurs after Content is Imported and Saved - /// - public static event TypedEventHandler> ImportedContent; - - /// - /// Occurs before Importing ContentType - /// - public static event TypedEventHandler> ImportingContentType; - - /// - /// Occurs after ContentType is Imported and Saved - /// - public static event TypedEventHandler> ImportedContentType; - - /// - /// Occurs before Importing DataType - /// - public static event TypedEventHandler> ImportingDataType; - - /// - /// Occurs after DataType is Imported and Saved - /// - public static event TypedEventHandler> ImportedDataType; - - /// - /// Occurs before Importing DictionaryItem - /// - public static event TypedEventHandler> ImportingDictionaryItem; - - /// - /// Occurs after DictionaryItem is Imported and Saved - /// - public static event TypedEventHandler> ImportedDictionaryItem; - - /// - /// Occurs before Importing Macro - /// - public static event TypedEventHandler> ImportingMacro; - - /// - /// Occurs after Macro is Imported and Saved - /// - public static event TypedEventHandler> ImportedMacro; - - /// - /// Occurs before Importing Language - /// - public static event TypedEventHandler> ImportingLanguage; - - /// - /// Occurs after Language is Imported and Saved - /// - public static event TypedEventHandler> ImportedLanguage; - - /// - /// Occurs before Importing Template - /// - public static event TypedEventHandler> ImportingTemplate; - - /// - /// Occurs before Importing Stylesheets - /// - public static event TypedEventHandler> ImportingStylesheets; - - /// - /// Occurs after Template is Imported and Saved - /// - public static event TypedEventHandler> ImportedTemplate; /// /// Occurs before Importing umbraco package diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 2ee5d13f6d..b59a5190bd 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -320,7 +320,6 @@ - @@ -447,9 +446,11 @@ + + @@ -573,7 +574,6 @@ - diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index fe7a5fbe5c..964f0c47de 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -4,9 +4,11 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Tests.TestHelpers; @@ -38,10 +40,16 @@ namespace Umbraco.Tests.Packaging private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser(new ConflictingPackageData(ServiceContext.MacroService, ServiceContext.FileService)); + private PackageDataInstallation PackageDataInstallation => new PackageDataInstallation( + Logger, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, + ServiceContext.DataTypeService, ServiceContext.EntityService, + ServiceContext.ContentTypeService, ServiceContext.ContentService, + Factory.GetInstance()); + private IPackageInstallation PackageInstallation => new PackageInstallation( - ServiceContext.PackagingService, + PackageDataInstallation, new PackageFileInstallation(Parser, ProfilingLogger), - Parser, + Parser, Mock.Of(), packagesFolderPath: "~/Packaging/packages",//this is where our test zip file is applicationRootFolder: new DirectoryInfo(IOHelper.GetRootDirectorySafe()), packageExtractionFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs index 84eb75a4f7..f29a43c504 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Composing.Composers; using Umbraco.Core.Logging; +using Umbraco.Core.Packaging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -65,6 +66,8 @@ namespace Umbraco.Tests.Services.Importing Composition.ComposeFileSystems(); } + private PackageDataInstallation PackagingService => Factory.GetInstance(); + [Test] public void PackagingService_Can_Import_uBlogsy_ContentTypes_And_Verify_Structure() { @@ -74,12 +77,11 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var templateElement = xml.Descendants("Templates").First(); var docTypeElement = xml.Descendants("DocumentTypes").First(); - var packagingService = ServiceContext.PackagingService; // Act - var dataTypes = packagingService.ImportDataTypeDefinitions(dataTypeElement); - var templates = packagingService.ImportTemplates(templateElement); - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var dataTypes = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); @@ -122,12 +124,11 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var templateElement = xml.Descendants("Templates").First(); var docTypeElement = xml.Descendants("DocumentTypes").First(); - var packagingService = ServiceContext.PackagingService; // Act - var dataTypes = packagingService.ImportDataTypeDefinitions(dataTypeElement); - var templates = packagingService.ImportTemplates(templateElement); - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var dataTypes = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); // Assert var mRBasePage = contentTypes.First(x => x.Alias == "MRBasePage"); @@ -148,12 +149,11 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var templateElement = xml.Descendants("Templates").First(); var docTypeElement = xml.Descendants("DocumentTypes").First(); - var packagingService = ServiceContext.PackagingService; // Act - var dataTypes = packagingService.ImportDataTypeDefinitions(dataTypeElement); - var templates = packagingService.ImportTemplates(templateElement); - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var dataTypes = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); @@ -186,11 +186,11 @@ namespace Umbraco.Tests.Services.Importing string strXml = ImportResources.StandardMvc_Package; var xml = XElement.Parse(strXml); var element = xml.Descendants("Templates").First(); - var packagingService = ServiceContext.PackagingService; + var init = ServiceContext.FileService.GetTemplates().Count(); // Act - var templates = packagingService.ImportTemplates(element); + var templates = PackagingService.ImportTemplates(element.Elements("Template").ToList(), 0); var numberOfTemplates = (from doc in element.Elements("Template") select doc).Count(); var allTemplates = ServiceContext.FileService.GetTemplates(); @@ -209,11 +209,11 @@ namespace Umbraco.Tests.Services.Importing // Arrange string strXml = ImportResources.StandardMvc_Package; var xml = XElement.Parse(strXml); - var element = xml.Descendants("Templates").First().Element("Template"); - var packagingService = ServiceContext.PackagingService; + var element = xml.Descendants("Templates").First(); + // Act - var templates = packagingService.ImportTemplates(element); + var templates = PackagingService.ImportTemplate(element.Elements("Template").First(), 0); // Assert Assert.That(templates, Is.Not.Null); @@ -230,12 +230,12 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var templateElement = xml.Descendants("Templates").First(); var docTypeElement = xml.Descendants("DocumentTypes").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement); - var templates = packagingService.ImportTemplates(templateElement); - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); // Assert @@ -268,13 +268,13 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypeDefinitions = ServiceContext.PackagingService.ImportDataTypeDefinitions(dataTypeElement); - var templates = ServiceContext.PackagingService.ImportTemplates(templateElement); - var contentTypes = ServiceContext.PackagingService.ImportContentTypes(docTypeElement); + var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); //Assert - Re-Import contenttypes doesn't throw - Assert.DoesNotThrow(() => ServiceContext.PackagingService.ImportContentTypes(docTypeElement)); + Assert.DoesNotThrow(() => PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0)); Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); Assert.That(dataTypeDefinitions, Is.Not.Null); Assert.That(dataTypeDefinitions.Any(), Is.True); @@ -292,13 +292,13 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypeDefinitions = ServiceContext.PackagingService.ImportDataTypeDefinitions(dataTypeElement); - var templates = ServiceContext.PackagingService.ImportTemplates(templateElement); - var contentTypes = ServiceContext.PackagingService.ImportContentTypes(docTypeElement); + var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); //Assert - Re-Import contenttypes doesn't throw - Assert.DoesNotThrow(() => ServiceContext.PackagingService.ImportContentTypes(docTypeElement)); + Assert.DoesNotThrow(() => PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0)); Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); Assert.That(dataTypeDefinitions, Is.Not.Null); Assert.That(dataTypeDefinitions.Any(), Is.True); @@ -314,12 +314,13 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var docTypesElement = xml.Descendants("DocumentTypes").First(); var element = xml.Descendants("DocumentSet").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement); - var contentTypes = packagingService.ImportContentTypes(docTypesElement); - var contents = packagingService.ImportContent(element); + var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); + var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); + var contents = PackagingService.ImportContent(element, -1, importedContentTypes, 0); var numberOfDocs = (from doc in element.Descendants() where (string) doc.Attribute("isDoc") == "" select doc).Count(); @@ -347,12 +348,13 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var docTypesElement = xml.Descendants("DocumentTypes").First(); var element = xml.Descendants("DocumentSet").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement); - var contentTypes = packagingService.ImportContentTypes(docTypesElement); - var contents = packagingService.ImportContent(element); + var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); + var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); + var contents = PackagingService.ImportContent(element, -1, importedContentTypes, 0); var numberOfDocs = (from doc in element.Descendants() where (string)doc.Attribute("isDoc") == "" select doc).Count(); @@ -382,10 +384,10 @@ namespace Umbraco.Tests.Services.Importing string strXml = ImportResources.XsltSearch_Package; var xml = XElement.Parse(strXml); var templateElement = xml.Descendants("Templates").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var templates = packagingService.ImportTemplates(templateElement); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); // Assert @@ -399,10 +401,10 @@ namespace Umbraco.Tests.Services.Importing // Arrange string strXml = ImportResources.SingleDocType; var docTypeElement = XElement.Parse(strXml); - var packagingService = ServiceContext.PackagingService; + // Act - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var contentTypes = PackagingService.ImportDocumentType(docTypeElement, 0); // Assert Assert.That(contentTypes.Any(), Is.True); @@ -416,11 +418,11 @@ namespace Umbraco.Tests.Services.Importing // Arrange string strXml = ImportResources.SingleDocType; var docTypeElement = XElement.Parse(strXml); - var packagingService = ServiceContext.PackagingService; + var serializer = Factory.GetInstance(); // Act - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var contentTypes = PackagingService.ImportDocumentType(docTypeElement, 0); var contentType = contentTypes.FirstOrDefault(); var element = serializer.Serialize(contentType); @@ -442,8 +444,8 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = XElement.Parse(strXml); // Act - var contentTypes = ServiceContext.PackagingService.ImportContentTypes(docTypeElement); - var contentTypesUpdated = ServiceContext.PackagingService.ImportContentTypes(docTypeElement); + var contentTypes = PackagingService.ImportDocumentType(docTypeElement, 0); + var contentTypesUpdated = PackagingService.ImportDocumentType(docTypeElement, 0); // Assert Assert.That(contentTypes.Any(), Is.True); @@ -465,7 +467,7 @@ namespace Umbraco.Tests.Services.Importing var templateElement = newPackageXml.Descendants("Templates").First(); var templateElementUpdated = updatedPackageXml.Descendants("Templates").First(); - var packagingService = ServiceContext.PackagingService; + var fileService = ServiceContext.FileService; // kill default test data @@ -473,8 +475,8 @@ namespace Umbraco.Tests.Services.Importing // Act var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); - var templates = packagingService.ImportTemplates(templateElement); - var templatesAfterUpdate = packagingService.ImportTemplates(templateElementUpdated); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var templatesAfterUpdate = PackagingService.ImportTemplates(templateElementUpdated.Elements("Template").ToList(), 0); var allTemplates = fileService.GetTemplates(); // Assert @@ -500,7 +502,7 @@ namespace Umbraco.Tests.Services.Importing AddLanguages(); // Act - ServiceContext.PackagingService.ImportDictionaryItems(dictionaryItemsElement); + PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert AssertDictionaryItem("Parent", expectedEnglishParentValue, "en-GB"); @@ -522,7 +524,7 @@ namespace Umbraco.Tests.Services.Importing AddLanguages(); // Act - var dictionaryItems = ServiceContext.PackagingService.ImportDictionaryItems(dictionaryItemsElement); + var dictionaryItems = PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(parentKey), "DictionaryItem parentKey does not exist"); @@ -551,7 +553,7 @@ namespace Umbraco.Tests.Services.Importing AddExistingEnglishAndNorwegianParentDictionaryItem(expectedEnglishParentValue, expectedNorwegianParentValue); // Act - ServiceContext.PackagingService.ImportDictionaryItems(dictionaryItemsElement); + PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert AssertDictionaryItem("Parent", expectedEnglishParentValue, "en-GB"); @@ -576,7 +578,7 @@ namespace Umbraco.Tests.Services.Importing AddExistingEnglishParentDictionaryItem(expectedEnglishParentValue); // Act - ServiceContext.PackagingService.ImportDictionaryItems(dictionaryItemsElement); + PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert AssertDictionaryItem("Parent", expectedEnglishParentValue, "en-GB"); @@ -593,7 +595,7 @@ namespace Umbraco.Tests.Services.Importing var LanguageItemsElement = newPackageXml.Elements("Languages").First(); // Act - var languages = ServiceContext.PackagingService.ImportLanguages(LanguageItemsElement); + var languages = PackagingService.ImportLanguages(LanguageItemsElement.Elements("Language"), 0); var allLanguages = ServiceContext.LocalizationService.GetAllLanguages(); // Assert @@ -611,10 +613,10 @@ namespace Umbraco.Tests.Services.Importing string strXml = ImportResources.uBlogsy_Package; var xml = XElement.Parse(strXml); var macrosElement = xml.Descendants("Macros").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var macros = packagingService.ImportMacros(macrosElement).ToList(); + var macros = PackagingService.ImportMacros(macrosElement.Elements("macro"), 0).ToList(); // Assert Assert.That(macros.Any(), Is.True); @@ -633,10 +635,10 @@ namespace Umbraco.Tests.Services.Importing string strXml = ImportResources.XsltSearch_Package; var xml = XElement.Parse(strXml); var macrosElement = xml.Descendants("Macros").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var macros = packagingService.ImportMacros(macrosElement).ToList(); + var macros = PackagingService.ImportMacros(macrosElement.Elements("macro"), 0).ToList(); // Assert Assert.That(macros.Any(), Is.True); @@ -657,11 +659,11 @@ namespace Umbraco.Tests.Services.Importing var xml = XElement.Parse(strXml); var templateElement = xml.Descendants("Templates").First(); var docTypeElement = xml.Descendants("DocumentTypes").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var templates = packagingService.ImportTemplates(templateElement); - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); // Assert @@ -685,10 +687,10 @@ namespace Umbraco.Tests.Services.Importing string strXml = ImportResources.CompositionsTestPackage_Random; var xml = XElement.Parse(strXml); var docTypeElement = xml.Descendants("DocumentTypes").First(); - var packagingService = ServiceContext.PackagingService; + // Act - var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); // Assert diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index f48b72daf9..412a492376 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -22,6 +22,7 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web.Services; namespace Umbraco.Tests.TestHelpers @@ -78,9 +79,11 @@ namespace Umbraco.Tests.TestHelpers /// A cache. /// A logger. /// + /// /// An event messages factory. /// Some url segment providers. - /// A container. + /// + /// A container. /// /// A ServiceContext. /// Should be used sparingly for integration tests only - for unit tests @@ -168,12 +171,22 @@ namespace Umbraco.Tests.TestHelpers GetRepo(c))); var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); - var packagingService = GetLazyService(factory, c => new PackagingService( - logger, contentService.Value, contentTypeService.Value, macroService.Value, dataTypeService.Value, fileService.Value, localizationService.Value, entityService.Value, auditService.Value, new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())), - createdPackages: new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, - new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "createdPackages.config"), - installedPackages: new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, - new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "installedPackages.config"))); + var packagingService = GetLazyService(factory, c => + { + var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); + var compiledPackageXmlParser = new CompiledPackageXmlParser(new ConflictingPackageData(macroService.Value, fileService.Value)); + return new PackagingService( + auditService.Value, + new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "createdPackages.config"), + new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, + new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders), logger, "installedPackages.config"), + new PackageInstallation( + new PackageDataInstallation(logger, fileService.Value, macroService.Value, localizationService.Value, dataTypeService.Value, entityService.Value, contentTypeService.Value, contentService.Value, propertyEditorCollection), + new PackageFileInstallation(compiledPackageXmlParser, new ProfilingLogger(logger, new TestProfiler())), + compiledPackageXmlParser, Mock.Of(), + "", null, null)); + }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index daf152c29b..860d3ec88e 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -216,7 +216,7 @@ namespace Umbraco.Web.Composing internal static ManifestValueValidatorCollection ManifestValidators => CoreCurrent.ManifestValidators; - internal static PackageActionRunner PackageActionRunner => CoreCurrent.PackageActionRunner; + internal static IPackageActionRunner PackageActionRunner => CoreCurrent.PackageActionRunner; internal static PackageActionCollection PackageActions => CoreCurrent.PackageActions; diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 0d56b34617..97f7ff3589 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -17,7 +17,9 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Web.Composing; @@ -46,10 +48,19 @@ namespace Umbraco.Web.Editors public class ContentTypeController : ContentTypeControllerBase { private readonly IEntityXmlSerializer _serializer; + private readonly PropertyEditorCollection _propertyEditors; - public ContentTypeController(IEntityXmlSerializer serializer, ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public ContentTypeController(IEntityXmlSerializer serializer, + ICultureDictionaryFactory cultureDictionaryFactory, + IGlobalSettings globalSettings, + IUmbracoContextAccessor umbracoContextAccessor, + ISqlContext sqlContext, PropertyEditorCollection propertyEditors, + ServiceContext services, CacheHelper applicationCache, + IProfilingLogger logger, IRuntimeState runtimeState) + : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { _serializer = serializer; + _propertyEditors = propertyEditors; } public int GetCount() @@ -162,8 +173,8 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var configuration = Current.Services.DataTypeService.GetDataType(id).Configuration; - var editor = Current.PropertyEditors[dataTypeDiff.EditorAlias]; + var configuration = Services.DataTypeService.GetDataType(id).Configuration; + var editor = _propertyEditors[dataTypeDiff.EditorAlias]; return new ContentPropertyDisplay() { @@ -488,14 +499,16 @@ namespace Umbraco.Web.Editors { return Request.CreateResponse(HttpStatusCode.NotFound); } + + var dataInstaller = new PackageDataInstallation(Logger, Services.FileService, Services.MacroService, Services.LocalizationService, + Services.DataTypeService, Services.EntityService, Services.ContentTypeService, Services.ContentService, _propertyEditors); - var xd = new XmlDocument(); - xd.XmlResolver = null; + var xd = new XmlDocument {XmlResolver = null}; xd.Load(filePath); - var userId = Security.GetUserId(); + var userId = Security.GetUserId().ResultOr(0); var element = XElement.Parse(xd.InnerXml); - Current.Services.PackagingService.ImportContentTypes(element, userId); + dataInstaller.ImportDocumentType(element, userId); // Try to clean up the temporary file. try @@ -504,7 +517,7 @@ namespace Umbraco.Web.Editors } catch (Exception ex) { - Current.Logger.Error(ex, "Error cleaning up temporary udt file in App_Data: {File}", filePath); + Logger.Error(ex, "Error cleaning up temporary udt file in App_Data: {File}", filePath); } return Request.CreateResponse(HttpStatusCode.OK); diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 24cc999c6b..bfaec3f82c 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -42,11 +42,11 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageInstallController : UmbracoAuthorizedJsonController { - private readonly PackageActionRunner _packageActionRunner; + private readonly IPackageActionRunner _packageActionRunner; public PackageInstallController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, - IProfilingLogger logger, IRuntimeState runtimeState, PackageActionRunner packageActionRunner) + IProfilingLogger logger, IRuntimeState runtimeState, IPackageActionRunner packageActionRunner) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { _packageActionRunner = packageActionRunner; @@ -259,6 +259,7 @@ namespace Umbraco.Web.Editors }; // trigger the UninstalledPackage event + // fixme: This all needs to be part of the service! PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs(summary, package, false)); } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 64e17af221..89260e59f6 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1136,7 +1136,6 @@ - diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs deleted file mode 100644 index 89dff406b0..0000000000 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ /dev/null @@ -1,688 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Diagnostics; -//using System.Globalization; -//using System.IO; -//using System.Linq; -//using System.Net; -//using System.Xml; -//using System.Xml.Linq; -//using System.Xml.XPath; -//using ICSharpCode.SharpZipLib.Zip; -//using Umbraco.Core; -//using Umbraco.Core.Composing; -//using Umbraco.Core.Events; -//using Umbraco.Core.IO; -//using Umbraco.Core.Logging; -//using Umbraco.Core.Models; -//using Umbraco.Core.Models.Packaging; -//using Umbraco.Core.Packaging; -//using Umbraco.Core.Services.Implement; -//using File = System.IO.File; - -//namespace Umbraco.Web._Legacy.Packager -//{ -// /// -// /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. -// /// -// /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documentTypes (etc.) -// /// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.) -// /// -// /// Partly implemented, import of packages is done, the export is *under construction*. -// /// -// /// -// /// Ruben Verborgh 31/12/2007: I had to change some code, I marked my changes with "DATALAYER". -// /// Reason: @@IDENTITY can't be used with the new datalayer. -// /// I wasn't able to test the code, since I'm not aware how the code functions. -// /// -// public class Installer -// { -// private const string PackageServer = "packages.umbraco.org"; - -// private readonly Dictionary _conflictingMacroAliases = new Dictionary(); -// private readonly Dictionary _conflictingTemplateAliases = new Dictionary(); -// private readonly Dictionary _conflictingStyleSheetNames = new Dictionary(); - -// private readonly int _currentUserId = -1; -// private static WebClient _webClient; - - -// public string Name { get; private set; } -// public string Version { get; private set; } -// public string Url { get; private set; } -// public string License { get; private set; } -// public string LicenseUrl { get; private set; } -// public string Author { get; private set; } -// public string AuthorUrl { get; private set; } -// public string ReadMe { get; private set; } -// public string Control { get; private set; } - -// public bool ContainsMacroConflict { get; private set; } -// public IDictionary ConflictingMacroAliases => _conflictingMacroAliases; - -// public bool ContainsUnsecureFiles { get; private set; } -// public List UnsecureFiles { get; } = new List(); - -// public bool ContainsTemplateConflicts { get; private set; } -// public IDictionary ConflictingTemplateAliases => _conflictingTemplateAliases; - -// public bool ContainsStyleSheeConflicts { get; private set; } -// public IDictionary ConflictingStyleSheetNames => _conflictingStyleSheetNames; - -// public int RequirementsMajor { get; private set; } -// public int RequirementsMinor { get; private set; } -// public int RequirementsPatch { get; private set; } - -// public RequirementsType RequirementsType { get; private set; } - -// public string IconUrl { get; private set; } - -// /// -// /// The xml of the compiled package -// /// -// public XDocument Config { get; private set; } - -// /// -// /// Constructor -// /// -// public Installer() -// { -// Initialize(); -// } - -// public Installer(int currentUserId) -// { -// Initialize(); -// _currentUserId = currentUserId; -// } - -// private void Initialize() -// { -// ContainsTemplateConflicts = false; -// ContainsUnsecureFiles = false; -// ContainsMacroConflict = false; -// ContainsStyleSheeConflicts = false; -// } - - - -// /// -// /// Constructor -// /// -// /// The name of the package -// /// The version of the package -// /// The url to a descriptionpage -// /// The license under which the package is released (preferably GPL ;)) -// /// The url to a licensedescription -// /// The original author of the package -// /// The url to the Authors website -// /// Umbraco version major -// /// Umbraco version minor -// /// Umbraco version patch -// /// The readme text -// /// The name of the usercontrol used to configure the package after install -// /// -// /// -// public Installer(string name, string version, string url, string license, string licenseUrl, string author, string authorUrl, int requirementsMajor, int requirementsMinor, int requirementsPatch, string readme, string control, RequirementsType requirementsType, string iconUrl) -// { -// ContainsTemplateConflicts = false; -// ContainsUnsecureFiles = false; -// ContainsMacroConflict = false; -// ContainsStyleSheeConflicts = false; -// this.Name = name; -// this.Version = version; -// this.Url = url; -// this.License = license; -// this.LicenseUrl = licenseUrl; -// this.RequirementsMajor = requirementsMajor; -// this.RequirementsMinor = requirementsMinor; -// this.RequirementsPatch = requirementsPatch; -// this.RequirementsType = requirementsType; -// this.Author = author; -// this.AuthorUrl = authorUrl; -// this.IconUrl = iconUrl; -// ReadMe = readme; -// this.Control = control; -// } - -// #region Public Methods - -// /// -// /// Imports the specified package -// /// -// /// Filename of the umbracopackage -// /// true if the input file should be deleted after import -// /// -// public string Import(string inputFile, bool deleteFile) -// { -// using (Current.ProfilingLogger.DebugDuration( -// $"Importing package file {inputFile}.", -// $"Package file {inputFile} imported.")) -// { -// var tempDir = ""; -// if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + "/" + inputFile))) -// { -// var fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + "/" + inputFile)); -// // Check if the file is a valid package -// if (fi.Extension.ToLower() == ".umb") -// { -// try -// { -// tempDir = UnPack(fi.FullName, deleteFile); -// LoadConfig(tempDir); -// } -// catch (Exception ex) -// { -// Current.Logger.Error(ex, "Error importing file {FileName}", fi.FullName); -// throw; -// } -// } -// else -// throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download."); -// } -// else -// throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + inputFile) + "'"); -// return tempDir; -// } - -// } - -// /// -// /// Imports the specified package -// /// -// /// Filename of the umbracopackage -// /// -// public string Import(string inputFile) -// { -// return Import(inputFile, true); -// } - -// public int CreateManifest(Guid guid) -// { -// //This is the new improved install rutine, which chops up the process into 3 steps, creating the manifest, moving files, and finally handling umb objects - -// var parser = new CompiledPackageXmlParser(); -// var def = parser.ToCompiledPackage(Config); - -// //create a new entry in the installedPackages.config -// var installedPackage = new PackageDefinition -// { -// Author = def.Author, -// AuthorUrl = def.AuthorUrl, -// Control = def.Control, -// IconUrl = def.IconUrl, -// License = def.License, -// LicenseUrl = def.LicenseUrl, -// Name = def.Name, -// Readme = def.Readme, -// UmbracoVersion = def.UmbracoVersion, -// Url = def.Url, -// Version = def.Version, -// PackageId = guid -// }; - -// if (!Current.Services.PackagingService.SaveInstalledPackage(installedPackage)) -// throw new InvalidOperationException("Could not save package definition"); - -// return installedPackage.Id; -// } - -// public void InstallFiles(int packageId, string tempDir) -// { -// var parser = new CompiledPackageXmlParser(); - -// using (Current.ProfilingLogger.DebugDuration( -// "Installing package files for package id " + packageId + " into temp folder " + tempDir, -// "Package file installation complete for package id " + packageId)) -// { -// //retrieve the manifest to continue installation -// var insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); - -// //TODO: Depending on some files, some files should be installed differently. -// //i.e. if stylsheets should probably be installed via business logic, media items should probably use the media IFileSystem! - -// // Move files -// //string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath; -// string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; - -// var def = parser.ToCompiledPackage(Config); - -// try -// { -// foreach (var f in def.Files) -// { -// var destPath = GetFileName(basePath, f.OriginalPath); -// var sourceFile = GetFileName(tempDir, f.UniqueFileName); -// var destFile = GetFileName(destPath, f.OriginalName); - -// // Create the destination directory if it doesn't exist -// if (Directory.Exists(destPath) == false) -// Directory.CreateDirectory(destPath); -// //If a file with this name exists, delete it -// else if (File.Exists(destFile)) -// File.Delete(destFile); - -// // Copy the file -// // SJ: Note - this used to do a move but some packages included the same file to be -// // copied to multiple locations like so: -// // -// // -// // my-icon.png -// // /umbraco/Images/ -// // my-icon.png -// // -// // -// // my-icon.png -// // /App_Plugins/MyPlugin/Images -// // my-icon.png -// // -// // -// // Since this file unzips as a flat list of files, moving the file the first time means -// // that when you try to do that a second time, it would result in a FileNotFoundException -// File.Copy(sourceFile, destFile); - -// //PPH log file install -// insPack.Files.Add(f.OriginalPath.EnsureEndsWith('/') + f.OriginalName); - -// } - -// // Once we're done copying, remove all the files -// foreach (var f in def.Files) -// { -// var sourceFile = GetFileName(tempDir, f.UniqueFileName); -// if (File.Exists(sourceFile)) -// File.Delete(sourceFile); -// } -// } -// catch (Exception ex) -// { -// Current.Logger.Error(ex, "Package install error"); -// throw; -// } - -// // log that a user has install files -// if (_currentUserId > -1) -// { -// Current.Services.AuditService.Add(AuditType.PackagerInstall, -// _currentUserId, -// -1, "Package", string.Format("Package '{0}' installed. Package guid: {1}", insPack.Name, insPack.PackageId)); -// } - -// Current.Services.PackagingService.SaveInstalledPackage(insPack); -// } -// } - -// public void InstallBusinessLogic(int packageId, string tempDir) -// { -// using (Current.ProfilingLogger.DebugDuration( -// "Installing business logic for package id " + packageId + " into temp folder " + tempDir, -// "Package business logic installation complete for package id " + packageId)) -// { -// PackageDefinition insPack; -// try -// { -// //retrieve the manifest to continue installation -// insPack = Current.Services.PackagingService.GetInstalledPackageById(packageId); -// //bool saveNeeded = false; - -// // Get current user, with a fallback -// var currentUser = Current.Services.UserService.GetUserById(Constants.Security.SuperUserId); - -// //TODO: Get rid of this entire class! Until then all packages will be installed by the admin user - -// var rootElement = Config.Root; -// var packagingService = Current.Services.PackagingService; - -// //Perhaps it would have been a good idea to put the following into methods eh?!? - -// #region DataTypes -// var dataTypeElement = rootElement.Descendants("DataTypes").FirstOrDefault(); -// if (dataTypeElement != null) -// { -// var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement, currentUser.Id); -// foreach (var dataTypeDefinition in dataTypeDefinitions) -// { -// insPack.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); -// } -// } -// #endregion - -// #region Languages -// var languageItemsElement = rootElement.Descendants("Languages").FirstOrDefault(); -// if (languageItemsElement != null) -// { -// var insertedLanguages = packagingService.ImportLanguages(languageItemsElement); -// foreach(var x in insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))) -// insPack.Languages.Add(x); -// } - -// #endregion - -// #region Dictionary items -// var dictionaryItemsElement = rootElement.Descendants("DictionaryItems").FirstOrDefault(); -// if (dictionaryItemsElement != null) -// { -// var insertedDictionaryItems = packagingService.ImportDictionaryItems(dictionaryItemsElement); -// foreach (var x in insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))) -// insPack.DictionaryItems.Add(x); -// } -// #endregion - -// #region Macros -// var macroItemsElement = rootElement.Descendants("Macros").FirstOrDefault(); -// if (macroItemsElement != null) -// { -// var insertedMacros = packagingService.ImportMacros(macroItemsElement); -// foreach (var x in insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))) -// insPack.Macros.Add(x); - -// } -// #endregion - -// #region Templates -// var templateElement = rootElement.Descendants("Templates").FirstOrDefault(); -// if (templateElement != null) -// { -// var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); -// foreach (var template in templates) -// { -// insPack.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); -// } -// } -// #endregion - -// #region DocumentTypes -// //Check whether the root element is a doc type rather then a complete package -// var docTypeElement = rootElement.Name.LocalName.Equals("DocumentType") || -// rootElement.Name.LocalName.Equals("DocumentTypes") -// ? rootElement -// : rootElement.Descendants("DocumentTypes").FirstOrDefault(); - -// if (docTypeElement != null) -// { -// var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); -// foreach (var contentType in contentTypes) -// { -// insPack.DocumentTypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); -// //saveNeeded = true; -// } -// } -// #endregion - -// #region Stylesheets -// foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) -// { -// string stylesheetName = n.Element("Name")?.Value; -// if (stylesheetName.IsNullOrWhiteSpace()) continue; - -// var s = Current.Services.FileService.GetStylesheetByName(stylesheetName); -// if (s == null) -// { -// var fileName = n.Element("FileName")?.Value; -// if (fileName == null) continue; -// var content = n.Element("Content")?.Value; -// if (content == null) continue; - -// s = new Stylesheet(fileName) { Content = content }; -// Current.Services.FileService.SaveStylesheet(s); -// } - -// foreach (var prop in n.XPathSelectElements("Properties/Property")) -// { -// string alias = prop.Element("Alias")?.Value; -// var sp = s.Properties.SingleOrDefault(p => p != null && p.Alias == alias); -// string name = prop.Element("Name")?.Value; -// if (sp == null) -// { -// //sp = StylesheetProperty.MakeNew( -// // name, -// // s, -// // u); - -// sp = new StylesheetProperty(name, "#" + name.ToSafeAlias(), ""); -// s.AddProperty(sp); -// } -// else -// { -// //sp.Text = name; -// //Changing the name requires removing the current property and then adding another new one -// if (sp.Name != name) -// { -// s.RemoveProperty(sp.Name); -// var newProp = new StylesheetProperty(name, sp.Alias, sp.Value); -// s.AddProperty(newProp); -// sp = newProp; -// } -// } -// sp.Alias = alias; -// sp.Value = prop.Element("Value")?.Value; -// } -// //s.saveCssToFile(); -// Current.Services.FileService.SaveStylesheet(s); - - - - -// insPack.Stylesheets.Add(s.Id.ToString(CultureInfo.InvariantCulture)); -// //saveNeeded = true; -// } - -// //if (saveNeeded) { insPack.Save(); saveNeeded = false; } -// #endregion - -// #region Documents -// var documentElement = rootElement.Descendants("DocumentSet").FirstOrDefault(); -// if (documentElement != null) -// { -// var content = packagingService.ImportContent(documentElement, -1, currentUser.Id); -// var firstContentItem = content.First(); -// insPack.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); -// } -// #endregion - -// #region Package Actions -// foreach (var n in Config.Root.XPathSelectElements("Actions/Action")) -// { -// var undo = n.AttributeValue("undo"); -// if (undo == null || undo == "true") -// { -// insPack.Actions += n.ToString(); -// } - -// //Run the actions tagged only for 'install' -// var runat = n.AttributeValue("runat"); - -// if (runat != null && runat == "install") -// { -// var alias = n.AttributeValue("alias"); -// if (alias.IsNullOrWhiteSpace() == false) -// { -// Current.PackageActionRunner.RunPackageAction(insPack.Name, alias, n); -// } -// } -// } -// #endregion - -// Current.Services.PackagingService.SaveInstalledPackage(insPack); -// } -// catch (Exception ex) -// { -// Current.Logger.Error(ex, "Error installing businesslogic"); -// throw; -// } - -// OnPackageInstalled(insPack); -// } -// } - -// /// -// /// Remove the temp installation folder -// /// -// /// -// /// -// public void InstallCleanUp(int packageId, string tempDir) -// { -// if (Directory.Exists(tempDir)) -// { -// Directory.Delete(tempDir, true); -// } -// } - -// /// -// /// Reads the configuration of the package from the configuration xmldocument -// /// -// /// The folder to which the contents of the package is extracted -// public void LoadConfig(string tempDir) -// { -// Config = XDocument.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); - -// var parser = new CompiledPackageXmlParser(); -// var def = parser.ToCompiledPackage(Config); - -// Name = def.Name; -// Version = def.Version; -// Url = def.Url; -// License = def.License; -// LicenseUrl = def.LicenseUrl; - -// RequirementsMajor = def.UmbracoVersion.Major; -// RequirementsMinor = def.UmbracoVersion.Minor; -// RequirementsPatch = def.UmbracoVersion.Build; -// RequirementsType = def.UmbracoVersionRequirementsType; -// IconUrl = def.IconUrl; -// Author = def.Author; -// AuthorUrl = def.AuthorUrl; -// ReadMe = def.Readme; -// Control = def.Control; - -// var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; -// var dllBinFiles = new List(); - -// foreach (var f in def.Files) -// { -// var badFile = false; -// var destPath = GetFileName(basePath, f.OriginalPath); -// var orgName = f.OriginalName; -// var destFile = GetFileName(destPath, orgName); - -// if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) -// { -// badFile = true; -// } - -// if (destPath.ToLower().Contains(IOHelper.DirSepChar + "bin")) -// { -// badFile = true; -// } - -// if (destFile.ToLower().EndsWith(".dll")) -// { -// badFile = true; -// dllBinFiles.Add(Path.Combine(tempDir, orgName)); -// } - -// if (badFile) -// { -// ContainsUnsecureFiles = true; -// UnsecureFiles.Add(f.OriginalName); -// } -// } - - - -// //this will check for existing macros with the same alias -// //since we will not overwrite on import it's a good idea to inform the user what will be overwritten -// foreach (var n in Config.Root.XPathSelectElements("//macro")) -// { -// var alias = n.Element("alias")?.Value; -// if (!string.IsNullOrEmpty(alias)) -// { -// var m = Current.Services.MacroService.GetByAlias(alias); -// if (m != null) -// { -// ContainsMacroConflict = true; -// if (_conflictingMacroAliases.ContainsKey(m.Name) == false) -// { -// _conflictingMacroAliases.Add(m.Name, alias); -// } -// } -// } -// } - -// foreach (var n in Config.Root.XPathSelectElements("Templates/Template")) -// { -// var alias = n.Element("Alias")?.Value; -// if (!string.IsNullOrEmpty(alias)) -// { -// var t = Current.Services.FileService.GetTemplate(alias); -// if (t != null) -// { -// ContainsTemplateConflicts = true; -// if (_conflictingTemplateAliases.ContainsKey(t.Alias) == false) -// { -// _conflictingTemplateAliases.Add(t.Alias, alias); -// } -// } -// } -// } - -// foreach (var n in Config.Root.XPathSelectElements("Stylesheets/Stylesheet")) -// { -// var alias = n.Element("Name")?.Value; -// if (!string.IsNullOrEmpty(alias)) -// { -// var s = Current.Services.FileService.GetStylesheetByName(alias); -// if (s != null) -// { -// ContainsStyleSheeConflicts = true; -// if (_conflictingStyleSheetNames.ContainsKey(s.Alias) == false) -// { -// _conflictingStyleSheetNames.Add(s.Alias, alias); -// } -// } -// } -// } - - -// } - -// /// -// /// This uses the old method of fetching and only supports the packages.umbraco.org repository. -// /// -// /// -// /// -// public string Fetch(Guid Package) -// { -// // Check for package directory -// if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages)) == false) -// Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - -// if (_webClient == null) -// _webClient = new WebClient(); - -// _webClient.DownloadFile( -// "http://" + PackageServer + "/fetch?package=" + Package.ToString(), -// IOHelper.MapPath(SystemDirectories.Packages + "/" + Package + ".umb")); - -// return "packages\\" + Package + ".umb"; -// } - -// #endregion - -// private void OnPackageInstalled(PackageDefinition insPack) -// { -// // getting an InstallationSummary for sending to the PackagingService.ImportedPackage event -// var fileService = Current.Services.FileService; -// var macroService = Current.Services.MacroService; -// var contentTypeService = Current.Services.ContentTypeService; -// var dataTypeService = Current.Services.DataTypeService; -// var localizationService = Current.Services.LocalizationService; - -// var installationSummary = InstallationSummary.FromPackageDefinition(insPack, contentTypeService, dataTypeService, fileService, localizationService, macroService); -// installationSummary.PackageInstalled = true; - -// var args = new ImportPackageEventArgs(installationSummary, insPack, false); -// PackagingService.OnImportedPackage(args); -// } -// } -//} From aa6342cc30d2d0d13a72881ae63dd25e4ba68c83 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 14 Jan 2019 17:56:41 +1100 Subject: [PATCH 075/223] adds test --- .../Packaging/CompiledPackageXmlParser.cs | 18 +++++++-------- .../Packaging/PackageInstallationTest.cs | 22 ++++++++++++++++++- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 76f206f478..0f3119f697 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -52,7 +52,7 @@ namespace Umbraco.Core.Packaging UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type")), Control = package.Element("control")?.Value, - Actions = xml.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value + Actions = xml.Root.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value Files = xml.Root.Element("files")?.Elements("file")?.Select(x => new CompiledPackageFile { UniqueFileName = x.Element("guid")?.Value, @@ -60,14 +60,14 @@ namespace Umbraco.Core.Packaging OriginalPath = x.Element("orgPath")?.Value }).ToList() ?? new List(), - Macros = xml.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), - Templates = xml.Element("Templates")?.Elements("Template") ?? Enumerable.Empty(), - Stylesheets = xml.Element("Stylesheets")?.Elements("styleSheet") ?? Enumerable.Empty(), - DataTypes = xml.Element("DataTypes")?.Elements("DataType") ?? Enumerable.Empty(), - Languages = xml.Element("Languages")?.Elements("Language") ?? Enumerable.Empty(), - DictionaryItems = xml.Element("DictionaryItems")?.Elements("DictionaryItem") ?? Enumerable.Empty(), - DocumentTypes = xml.Element("DocumentTypes")?.Elements("DocumentType") ?? Enumerable.Empty(), - Documents = xml.Element("Documents")?.Elements("DocumentSet") ?? Enumerable.Empty(), + Macros = xml.Root.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), + Templates = xml.Root.Element("Templates")?.Elements("Template") ?? Enumerable.Empty(), + Stylesheets = xml.Root.Element("Stylesheets")?.Elements("styleSheet") ?? Enumerable.Empty(), + DataTypes = xml.Root.Element("DataTypes")?.Elements("DataType") ?? Enumerable.Empty(), + Languages = xml.Root.Element("Languages")?.Elements("Language") ?? Enumerable.Empty(), + DictionaryItems = xml.Root.Element("DictionaryItems")?.Elements("DictionaryItem") ?? Enumerable.Empty(), + DocumentTypes = xml.Root.Element("DocumentTypes")?.Elements("DocumentType") ?? Enumerable.Empty(), + Documents = xml.Root.Element("Documents")?.Elements("DocumentSet") ?? Enumerable.Empty(), }; def.Warnings = GetPreInstallWarnings(def, applicationRootFolder); diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 964f0c47de..609d26aec9 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -87,7 +87,7 @@ namespace Umbraco.Tests.Packaging Assert.AreEqual("@tentonipete", package.Author); Assert.AreEqual("auros.co.uk", package.AuthorUrl); Assert.AreEqual("Document Type Picker datatype that enables back office user to select one or many document types.", package.Readme); - + Assert.AreEqual(1, package.DataTypes.Count()); } [Test] @@ -114,6 +114,26 @@ namespace Umbraco.Tests.Packaging Assert.AreEqual(1, result.Count); Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", result[0]); Assert.IsTrue(File.Exists(Path.Combine(IOHelper.MapPath("~/" + _testBaseFolder), result[0]))); + + //make sure the def is updated too + Assert.AreEqual(result.Count(), def.Files.Count); + } + + [Test] + public void Install_Data() + { + var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var def = PackageDefinition.FromCompiledPackage(package); + def.Id = 1; + def.PackageId = Guid.NewGuid(); + + var summary = PackageInstallation.InstallPackageData(def, package, -1); + + Assert.AreEqual(1, summary.DataTypesInstalled.Count()); + + + //make sure the def is updated too + Assert.AreEqual(summary.DataTypesInstalled.Count(), def.DataTypes.Count); } From b3585b008395e28bcdeeaae02c0a42ea5255c24e Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 14 Jan 2019 18:03:06 +1100 Subject: [PATCH 076/223] some cleanup --- .../Models/Packaging/InstallationSummary.cs | 42 +------------------ .../Models/Packaging/PackageDefinition.cs | 8 ---- .../Packaging/PackageDefinitionXmlParser.cs | 2 - .../Packaging/PackagesRepository.cs | 4 +- .../CreatedPackagesRepositoryTests.cs | 2 - 5 files changed, 2 insertions(+), 56 deletions(-) diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index b14e3d2a92..7d81f48dd2 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using Umbraco.Core.IO; -using Umbraco.Core.Services; namespace Umbraco.Core.Models.Packaging { @@ -23,45 +21,7 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); public IEnumerable Actions { get; set; } = Enumerable.Empty(); public bool PackageInstalled { get; set; } - - //public static InstallationSummary FromPackageDefinition(PackageDefinition def, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService) - //{ - // var macros = TryGetIntegerIds(def.Macros).Select(macroService.GetById).ToList(); - // var templates = TryGetIntegerIds(def.Templates).Select(fileService.GetTemplate).ToList(); - // var contentTypes = TryGetIntegerIds(def.DocumentTypes).Select(contentTypeService.Get).ToList(); // fixme - media types? - // var dataTypes = TryGetIntegerIds(def.DataTypes).Select(dataTypeService.GetDataType).ToList(); - // var dictionaryItems = TryGetIntegerIds(def.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList(); - // var languages = TryGetIntegerIds(def.Languages).Select(localizationService.GetLanguageById).ToList(); - - // for (var i = 0; i < def.Files.Count; i++) - // { - // var filePath = def.Files[i]; - // def.Files[i] = filePath.GetRelativePath(); - // } - - // return new InstallationSummary - // { - // ContentTypesInstalled = contentTypes, - // DataTypesInstalled = dataTypes, - // DictionaryItemsInstalled = dictionaryItems, - // FilesInstalled = def.Files, - // LanguagesInstalled = languages, - // MacrosInstalled = macros, - // MetaData = def, - // TemplatesInstalled = templates, - // }; - //} - - //private static IEnumerable TryGetIntegerIds(IEnumerable ids) - //{ - // var intIds = new List(); - // foreach (var id in ids) - // { - // if (int.TryParse(id, out var parsed)) - // intIds.Add(parsed); - // } - // return intIds; - //} + } } diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index 56a316ff81..de8415ddd2 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -34,7 +34,6 @@ namespace Umbraco.Core.Models.Packaging UmbracoVersion = compiled.UmbracoVersion, Url = compiled.Url, Version = compiled.Version, - //fixme: Is OriginalPath correct here? Files = compiled.Files.Select(x => x.OriginalPath).ToList() }; } @@ -54,13 +53,6 @@ namespace Umbraco.Core.Models.Packaging [Url] public string Url { get; set; } = string.Empty; - //fixme: remove this - /// - /// This is a generated GUID which is used to determine a temporary folder name for processing the package - /// - [DataMember(Name = "folder")] - public Guid FolderId { get; set; } - [ReadOnly(true)] [DataMember(Name = "packagePath")] public string PackagePath { get; set; } = string.Empty; diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 9a996d201f..1f0e5ec92e 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -28,7 +28,6 @@ namespace Umbraco.Core.Packaging { Id = xml.AttributeValue("id"), Name = xml.AttributeValue("name") ?? string.Empty, - FolderId = xml.AttributeValue("folder"), PackagePath = xml.AttributeValue("packagePath") ?? string.Empty, Version = xml.AttributeValue("version") ?? string.Empty, Url = xml.AttributeValue("url") ?? string.Empty, @@ -74,7 +73,6 @@ namespace Umbraco.Core.Packaging new XAttribute("version", def.Version ?? string.Empty), new XAttribute("url", def.Url ?? string.Empty), new XAttribute("name", def.Name ?? string.Empty), - new XAttribute("folder", def.FolderId), new XAttribute("packagePath", def.PackagePath ?? string.Empty), new XAttribute("iconUrl", def.IconUrl ?? string.Empty), new XAttribute("umbVersion", def.UmbracoVersion), diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index 9f37f8a546..c0620820a2 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -131,7 +131,6 @@ namespace Umbraco.Core.Packaging var newId = maxId + 1; definition.Id = newId; definition.PackageId = definition.PackageId == default ? Guid.NewGuid() : definition.PackageId; - definition.FolderId = Guid.NewGuid(); var packageXml = _parser.ToXml(definition); packagesXml.Root.Add(packageXml); } @@ -155,13 +154,12 @@ namespace Umbraco.Core.Packaging { if (definition.Id == default) throw new ArgumentException("The package definition does not have an ID, it must be saved before being exported"); if (definition.PackageId == default) throw new ArgumentException("the package definition does not have a GUID, it must be saved before being exported"); - if (definition.FolderId == default) throw new ArgumentException("the package definition does not have a folder GUID, it must be saved before being exported"); //ensure it's valid ValidatePackage(definition); //Create a folder for building this package - var temporaryPath = IOHelper.MapPath(_tempFolderPath.EnsureEndsWith('/') + definition.FolderId); + var temporaryPath = IOHelper.MapPath(_tempFolderPath.EnsureEndsWith('/') + Guid.NewGuid()); if (Directory.Exists(temporaryPath) == false) Directory.CreateDirectory(temporaryPath); diff --git a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs index e059d87524..010572abec 100644 --- a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs @@ -83,7 +83,6 @@ namespace Umbraco.Tests.Packaging Assert.IsTrue(result); Assert.AreEqual(1, def1.Id); Assert.AreNotEqual(default(Guid).ToString(), def1.PackageId); - Assert.AreNotEqual(default(Guid).ToString(), def1.FolderId); var def2 = new PackageDefinition { @@ -98,7 +97,6 @@ namespace Umbraco.Tests.Packaging Assert.IsTrue(result); Assert.AreEqual(2, def2.Id); Assert.AreNotEqual(default(Guid).ToString(), def2.PackageId); - Assert.AreNotEqual(default(Guid).ToString(), def2.FolderId); } [Test] From fbf60fbac47eb0fe19074bab6e96c87330f6f220 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 22 Oct 2018 09:39:22 +0200 Subject: [PATCH 077/223] Don't add the "Notification" tree menu item if Umbraco can't send emails --- src/Umbraco.Web/Trees/ContentTreeController.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 293cc3d36a..54adb24b74 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -238,7 +238,10 @@ namespace Umbraco.Web.Trees menu.Items.Add(ui.Text("actions", ActionRights.Instance.Alias), true); menu.Items.Add(ui.Text("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.Items.Add(ui.Text("actions", ActionNotify.Instance.Alias), true); + if (EmailSender.CanSendRequiredEmail) + { + menu.Items.Add(ui.Text("actions", ActionNotify.Instance.Alias), true); + } menu.Items.Add(ui.Text("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); From b08e9226001f59d144fca943c59c5486964569b0 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 7 Nov 2018 12:27:50 +0100 Subject: [PATCH 078/223] Only allow setting up scheduled publishing if the user has the correct permissions to do so --- .../components/content/umbcontentnodeinfo.directive.js | 3 +++ .../src/views/components/content/umb-content-node-info.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 8f613469a3..c753ac67d2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -53,6 +53,9 @@ if (scope.documentType !== null) { scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id; } + + // only allow configuring scheduled publishing if the user has publish ("U") and unpublish ("Z") permissions on this node + scope.allowScheduledPublishing = _.contains(scope.node.allowedActions, "U") && _.contains(scope.node.allowedActions, "Z"); } scope.auditTrailPageChange = function (pageNumber) { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html index 7085babf59..0ed3986fe3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html @@ -107,7 +107,7 @@
- + From 05f1a24caff54e2ae9b6ec3f5289b9eb95410df9 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 14 Jan 2019 08:28:58 +0100 Subject: [PATCH 079/223] Fix duplicate IIS Express settings --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 81ca9c5a37..fc24d2b40f 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -1041,9 +1041,6 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" 7140 / http://localhost:7140 - 7131 - / - http://localhost:7131 False False From db8954e0a5d532943e9885581ef154cb21872cc4 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 14 Jan 2019 08:52:02 +0100 Subject: [PATCH 080/223] Verify that the current member is approved and not locked out (#3588) --- .../Routing/PublishedContentRequestEngine.cs | 853 +++++++++--------- 1 file changed, 438 insertions(+), 415 deletions(-) diff --git a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs index 217f407f02..0341c083f9 100644 --- a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs +++ b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs @@ -26,61 +26,61 @@ using RenderingEngine = Umbraco.Core.RenderingEngine; namespace Umbraco.Web.Routing { internal class PublishedContentRequestEngine - { - private readonly PublishedContentRequest _pcr; - private readonly RoutingContext _routingContext; - private readonly IWebRoutingSection _webRoutingSection; + { + private readonly PublishedContentRequest _pcr; + private readonly RoutingContext _routingContext; + private readonly IWebRoutingSection _webRoutingSection; - /// - /// Initializes a new instance of the class with a content request. - /// - /// - /// The content request. - public PublishedContentRequestEngine( + /// + /// Initializes a new instance of the class with a content request. + /// + /// + /// The content request. + public PublishedContentRequestEngine( IWebRoutingSection webRoutingSection, PublishedContentRequest pcr) - { - if (pcr == null) throw new ArgumentException("pcr is null."); - if (webRoutingSection == null) throw new ArgumentNullException("webRoutingSection"); - - _pcr = pcr; - _webRoutingSection = webRoutingSection; + { + if (pcr == null) throw new ArgumentException("pcr is null."); + if (webRoutingSection == null) throw new ArgumentNullException("webRoutingSection"); - _routingContext = pcr.RoutingContext; - if (_routingContext == null) throw new ArgumentException("pcr.RoutingContext is null."); - - var umbracoContext = _routingContext.UmbracoContext; - if (umbracoContext == null) throw new ArgumentException("pcr.RoutingContext.UmbracoContext is null."); - if (umbracoContext.RoutingContext != _routingContext) throw new ArgumentException("RoutingContext confusion."); - // no! not set yet. - //if (umbracoContext.PublishedContentRequest != _pcr) throw new ArgumentException("PublishedContentRequest confusion."); - } + _pcr = pcr; + _webRoutingSection = webRoutingSection; + + _routingContext = pcr.RoutingContext; + if (_routingContext == null) throw new ArgumentException("pcr.RoutingContext is null."); + + var umbracoContext = _routingContext.UmbracoContext; + if (umbracoContext == null) throw new ArgumentException("pcr.RoutingContext.UmbracoContext is null."); + if (umbracoContext.RoutingContext != _routingContext) throw new ArgumentException("RoutingContext confusion."); + // no! not set yet. + //if (umbracoContext.PublishedContentRequest != _pcr) throw new ArgumentException("PublishedContentRequest confusion."); + } protected ProfilingLogger ProfilingLogger - { + { get { return _routingContext.UmbracoContext.Application.ProfilingLogger; } - } + } - protected ServiceContext Services - { + protected ServiceContext Services + { get { return _routingContext.UmbracoContext.Application.Services; } - } + } - #region Public + #region Public /// /// Tries to route the request. /// - internal bool TryRouteRequest() - { + internal bool TryRouteRequest() + { // disabled - is it going to change the routing? //_pcr.OnPreparing(); FindDomain(); - if (_pcr.IsRedirect) return false; - if (_pcr.HasPublishedContent) return true; - FindPublishedContent(); + if (_pcr.IsRedirect) return false; + if (_pcr.HasPublishedContent) return true; + FindPublishedContent(); if (_pcr.IsRedirect) return false; // don't handle anything - we just want to ensure that we find the content @@ -93,51 +93,51 @@ namespace Umbraco.Web.Routing //_pcr.OnPrepared(); return _pcr.HasPublishedContent; - } + } - /// - /// Prepares the request. - /// - /// - /// Returns false if the request was not successfully prepared - /// - public bool PrepareRequest() - { - // note - at that point the original legacy module did something do handle IIS custom 404 errors - // ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support - // "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain - // to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk. - // - // to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors - // so that they point to a non-existing page eg /redirect-404.aspx - // TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means. + /// + /// Prepares the request. + /// + /// + /// Returns false if the request was not successfully prepared + /// + public bool PrepareRequest() + { + // note - at that point the original legacy module did something do handle IIS custom 404 errors + // ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support + // "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain + // to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk. + // + // to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors + // so that they point to a non-existing page eg /redirect-404.aspx + // TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means. // trigger the Preparing event - at that point anything can still be changed // the idea is that it is possible to change the uri // - _pcr.OnPreparing(); + _pcr.OnPreparing(); - //find domain - FindDomain(); + //find domain + FindDomain(); - // if request has been flagged to redirect then return - // whoever called us is in charge of actually redirecting - if (_pcr.IsRedirect) - { - return false; - } + // if request has been flagged to redirect then return + // whoever called us is in charge of actually redirecting + if (_pcr.IsRedirect) + { + return false; + } - // set the culture on the thread - once, so it's set when running document lookups - Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = _pcr.Culture; + // set the culture on the thread - once, so it's set when running document lookups + Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = _pcr.Culture; //find the published content if it's not assigned. This could be manually assigned with a custom route handler, or // with something like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler. Those in turn call this method // to setup the rest of the pipeline but we don't want to run the finders since there's one assigned. - if (_pcr.PublishedContent == null) - { + if (_pcr.PublishedContent == null) + { // find the document & template FindPublishedContentAndTemplate(); - } + } // handle wildcard domains HandleWildcardDomains(); @@ -145,19 +145,19 @@ namespace Umbraco.Web.Routing // set the culture on the thread -- again, 'cos it might have changed due to a finder or wildcard domain Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = _pcr.Culture; - // trigger the Prepared event - at that point it is still possible to change about anything + // trigger the Prepared event - at that point it is still possible to change about anything // even though the request might be flagged for redirection - we'll redirect _after_ the event // // also, OnPrepared() will make the PublishedContentRequest readonly, so nothing can change // - _pcr.OnPrepared(); + _pcr.OnPrepared(); // we don't take care of anything so if the content has changed, it's up to the user // to find out the appropriate template //complete the PCR and assign the remaining values - return ConfigureRequest(); - } + return ConfigureRequest(); + } /// /// Called by PrepareRequest once everything has been discovered, resolved and assigned to the PCR. This method @@ -210,73 +210,73 @@ namespace Umbraco.Web.Routing return true; } - /// - /// Updates the request when there is no template to render the content. - /// - /// This is called from Mvc when there's a document to render but no template. - public void UpdateRequestOnMissingTemplate() - { - // clear content - var content = _pcr.PublishedContent; - _pcr.PublishedContent = null; + /// + /// Updates the request when there is no template to render the content. + /// + /// This is called from Mvc when there's a document to render but no template. + public void UpdateRequestOnMissingTemplate() + { + // clear content + var content = _pcr.PublishedContent; + _pcr.PublishedContent = null; - HandlePublishedContent(); // will go 404 - FindTemplate(); + HandlePublishedContent(); // will go 404 + FindTemplate(); - // if request has been flagged to redirect then return - // whoever called us is in charge of redirecting - if (_pcr.IsRedirect) - return; + // if request has been flagged to redirect then return + // whoever called us is in charge of redirecting + if (_pcr.IsRedirect) + return; - if (_pcr.HasPublishedContent == false) - { - // means the engine could not find a proper document to handle 404 - // restore the saved content so we know it exists - _pcr.PublishedContent = content; - return; - } + if (_pcr.HasPublishedContent == false) + { + // means the engine could not find a proper document to handle 404 + // restore the saved content so we know it exists + _pcr.PublishedContent = content; + return; + } - if (_pcr.HasTemplate == false) - { - // means we may have a document, but we have no template - // at that point there isn't much we can do and there is no point returning - // to Mvc since Mvc can't do much either - return; - } + if (_pcr.HasTemplate == false) + { + // means we may have a document, but we have no template + // at that point there isn't much we can do and there is no point returning + // to Mvc since Mvc can't do much either + return; + } // see note in PrepareRequest() - // assign the legacy page back to the docrequest - // handlers like default.aspx will want it and most macros currently need it - _pcr.UmbracoPage = new page(_pcr); + // assign the legacy page back to the docrequest + // handlers like default.aspx will want it and most macros currently need it + _pcr.UmbracoPage = new page(_pcr); - // these two are used by many legacy objects - _routingContext.UmbracoContext.HttpContext.Items["pageID"] = _pcr.PublishedContent.Id; - _routingContext.UmbracoContext.HttpContext.Items["pageElements"] = _pcr.UmbracoPage.Elements; - } + // these two are used by many legacy objects + _routingContext.UmbracoContext.HttpContext.Items["pageID"] = _pcr.PublishedContent.Id; + _routingContext.UmbracoContext.HttpContext.Items["pageElements"] = _pcr.UmbracoPage.Elements; + } - #endregion + #endregion - #region Domain + #region Domain - /// - /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. - /// - /// A value indicating whether a domain was found. - internal bool FindDomain() - { - const string tracePrefix = "FindDomain: "; + /// + /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. + /// + /// A value indicating whether a domain was found. + internal bool FindDomain() + { + const string tracePrefix = "FindDomain: "; - // note - we are not handling schemes nor ports here. + // note - we are not handling schemes nor ports here. - ProfilingLogger.Logger.Debug("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri); + ProfilingLogger.Logger.Debug("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri); - // try to find a domain matching the current request + // try to find a domain matching the current request var domainAndUri = DomainHelper.DomainForUri(Services.DomainService.GetAll(false), _pcr.Uri); - // handle domain - if (domainAndUri != null && domainAndUri.UmbracoDomain.LanguageIsoCode.IsNullOrWhiteSpace() == false) - { + // handle domain + if (domainAndUri != null && domainAndUri.UmbracoDomain.LanguageIsoCode.IsNullOrWhiteSpace() == false) + { // matching an existing domain ProfilingLogger.Logger.Debug("{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"", () => tracePrefix, @@ -296,49 +296,49 @@ namespace Umbraco.Web.Routing // } } else - { - // not matching any existing domain - ProfilingLogger.Logger.Debug("{0}Matches no domain", () => tracePrefix); + { + // not matching any existing domain + ProfilingLogger.Logger.Debug("{0}Matches no domain", () => tracePrefix); var defaultLanguage = Services.LocalizationService.GetAllLanguages().FirstOrDefault(); - _pcr.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); - } + _pcr.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); + } - ProfilingLogger.Logger.Debug("{0}Culture=\"{1}\"", () => tracePrefix, () => _pcr.Culture.Name); + ProfilingLogger.Logger.Debug("{0}Culture=\"{1}\"", () => tracePrefix, () => _pcr.Culture.Name); - return _pcr.UmbracoDomain != null; - } + return _pcr.UmbracoDomain != null; + } - /// - /// Looks for wildcard domains in the path and updates Culture accordingly. - /// - internal void HandleWildcardDomains() - { - const string tracePrefix = "HandleWildcardDomains: "; + /// + /// Looks for wildcard domains in the path and updates Culture accordingly. + /// + internal void HandleWildcardDomains() + { + const string tracePrefix = "HandleWildcardDomains: "; - if (_pcr.HasPublishedContent == false) - return; + if (_pcr.HasPublishedContent == false) + return; - var nodePath = _pcr.PublishedContent.Path; - ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath); + var nodePath = _pcr.PublishedContent.Path; + ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath); var rootNodeId = _pcr.HasDomain ? _pcr.UmbracoDomain.RootContentId : (int?)null; var domain = DomainHelper.FindWildcardDomainInPath(Services.DomainService.GetAll(true), nodePath, rootNodeId); - if (domain != null && domain.LanguageIsoCode.IsNullOrWhiteSpace() == false) - { + if (domain != null && domain.LanguageIsoCode.IsNullOrWhiteSpace() == false) + { _pcr.Culture = new CultureInfo(domain.LanguageIsoCode); ProfilingLogger.Logger.Debug("{0}Got domain on node {1}, set culture to \"{2}\".", () => tracePrefix, () => domain.RootContentId, () => _pcr.Culture.Name); } - else - { - ProfilingLogger.Logger.Debug("{0}No match.", () => tracePrefix); - } - } + else + { + ProfilingLogger.Logger.Debug("{0}No match.", () => tracePrefix); + } + } - #endregion + #endregion - #region Rendering engine + #region Rendering engine /// /// Finds the rendering engine to use to render a template specified by its alias. @@ -383,264 +383,287 @@ namespace Umbraco.Web.Routing return directory.GetFiles().Any(f => extensions.Any(e => f.Name.InvariantEquals(alias + e))); } - #endregion + #endregion - #region Document and template + #region Document and template - /// - /// Finds the Umbraco document (if any) matching the request, and updates the PublishedContentRequest accordingly. - /// - /// A value indicating whether a document and template were found. - private void FindPublishedContentAndTemplate() - { - const string tracePrefix = "FindPublishedContentAndTemplate: "; - ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => _pcr.Uri.AbsolutePath); + /// + /// Finds the Umbraco document (if any) matching the request, and updates the PublishedContentRequest accordingly. + /// + /// A value indicating whether a document and template were found. + private void FindPublishedContentAndTemplate() + { + const string tracePrefix = "FindPublishedContentAndTemplate: "; + ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => _pcr.Uri.AbsolutePath); - // run the document finders - FindPublishedContent(); + // run the document finders + FindPublishedContent(); // if request has been flagged to redirect then return // whoever called us is in charge of actually redirecting // -- do not process anything any further -- if (_pcr.IsRedirect) - return; + return; - // not handling umbracoRedirect here but after LookupDocument2 - // so internal redirect, 404, etc has precedence over redirect + // not handling umbracoRedirect here but after LookupDocument2 + // so internal redirect, 404, etc has precedence over redirect - // handle not-found, redirects, access... - HandlePublishedContent(); + // handle not-found, redirects, access... + HandlePublishedContent(); - // find a template - FindTemplate(); + // find a template + FindTemplate(); - // handle umbracoRedirect - FollowExternalRedirect(); - } + // handle umbracoRedirect + FollowExternalRedirect(); + } - /// - /// Tries to find the document matching the request, by running the IPublishedContentFinder instances. - /// + /// + /// Tries to find the document matching the request, by running the IPublishedContentFinder instances. + /// /// There is no finder collection. - internal void FindPublishedContent() - { - const string tracePrefix = "FindPublishedContent: "; + internal void FindPublishedContent() + { + const string tracePrefix = "FindPublishedContent: "; - // look for the document - // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template - // some finders may implement caching + // look for the document + // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template + // some finders may implement caching using (ProfilingLogger.DebugDuration( - string.Format("{0}Begin finders", tracePrefix), - string.Format("{0}End finders, {1}", tracePrefix, (_pcr.HasPublishedContent ? "a document was found" : "no document was found")))) - { - if (_routingContext.PublishedContentFinders == null) + string.Format("{0}Begin finders", tracePrefix), + string.Format("{0}End finders, {1}", tracePrefix, (_pcr.HasPublishedContent ? "a document was found" : "no document was found")))) + { + if (_routingContext.PublishedContentFinders == null) throw new InvalidOperationException("There is no finder collection."); //iterate but return on first one that finds it - var found = _routingContext.PublishedContentFinders.Any(finder => finder.TryFindContent(_pcr)); - } + var found = _routingContext.PublishedContentFinders.Any(finder => finder.TryFindContent(_pcr)); + } - // indicate that the published content (if any) we have at the moment is the - // one that was found by the standard finders before anything else took place. - _pcr.SetIsInitialPublishedContent(); - } + // indicate that the published content (if any) we have at the moment is the + // one that was found by the standard finders before anything else took place. + _pcr.SetIsInitialPublishedContent(); + } - /// - /// Handles the published content (if any). - /// - /// - /// Handles "not found", internal redirects, access validation... - /// things that must be handled in one place because they can create loops - /// - private void HandlePublishedContent() - { - const string tracePrefix = "HandlePublishedContent: "; + /// + /// Handles the published content (if any). + /// + /// + /// Handles "not found", internal redirects, access validation... + /// things that must be handled in one place because they can create loops + /// + private void HandlePublishedContent() + { + const string tracePrefix = "HandlePublishedContent: "; - // because these might loop, we have to have some sort of infinite loop detection - int i = 0, j = 0; - const int maxLoop = 8; - do - { - ProfilingLogger.Logger.Debug("{0}{1}", () => tracePrefix, () => (i == 0 ? "Begin" : "Loop")); + // because these might loop, we have to have some sort of infinite loop detection + int i = 0, j = 0; + const int maxLoop = 8; + do + { + ProfilingLogger.Logger.Debug("{0}{1}", () => tracePrefix, () => (i == 0 ? "Begin" : "Loop")); - // handle not found - if (_pcr.HasPublishedContent == false) - { - _pcr.Is404 = true; - ProfilingLogger.Logger.Debug("{0}No document, try last chance lookup", () => tracePrefix); + // handle not found + if (_pcr.HasPublishedContent == false) + { + _pcr.Is404 = true; + ProfilingLogger.Logger.Debug("{0}No document, try last chance lookup", () => tracePrefix); - // if it fails then give up, there isn't much more that we can do - var lastChance = _routingContext.PublishedContentLastChanceFinder; - if (lastChance == null || lastChance.TryFindContent(_pcr) == false) - { - ProfilingLogger.Logger.Debug("{0}Failed to find a document, give up", () => tracePrefix); - break; - } + // if it fails then give up, there isn't much more that we can do + var lastChance = _routingContext.PublishedContentLastChanceFinder; + if (lastChance == null || lastChance.TryFindContent(_pcr) == false) + { + ProfilingLogger.Logger.Debug("{0}Failed to find a document, give up", () => tracePrefix); + break; + } - ProfilingLogger.Logger.Debug("{0}Found a document", () => tracePrefix); - } + ProfilingLogger.Logger.Debug("{0}Found a document", () => tracePrefix); + } - // follow internal redirects as long as it's not running out of control ie infinite loop of some sort - j = 0; - while (FollowInternalRedirects() && j++ < maxLoop) - { } - if (j == maxLoop) // we're running out of control - break; + // follow internal redirects as long as it's not running out of control ie infinite loop of some sort + j = 0; + while (FollowInternalRedirects() && j++ < maxLoop) + { } + if (j == maxLoop) // we're running out of control + break; - // ensure access - if (_pcr.HasPublishedContent) - EnsurePublishedContentAccess(); + // ensure access + if (_pcr.HasPublishedContent) + EnsurePublishedContentAccess(); - // loop while we don't have page, ie the redirect or access - // got us to nowhere and now we need to run the notFoundLookup again - // as long as it's not running out of control ie infinite loop of some sort + // loop while we don't have page, ie the redirect or access + // got us to nowhere and now we need to run the notFoundLookup again + // as long as it's not running out of control ie infinite loop of some sort - } while (_pcr.HasPublishedContent == false && i++ < maxLoop); + } while (_pcr.HasPublishedContent == false && i++ < maxLoop); - if (i == maxLoop || j == maxLoop) - { - ProfilingLogger.Logger.Debug("{0}Looks like we're running into an infinite loop, abort", () => tracePrefix); - _pcr.PublishedContent = null; - } + if (i == maxLoop || j == maxLoop) + { + ProfilingLogger.Logger.Debug("{0}Looks like we're running into an infinite loop, abort", () => tracePrefix); + _pcr.PublishedContent = null; + } - ProfilingLogger.Logger.Debug("{0}End", () => tracePrefix); - } + ProfilingLogger.Logger.Debug("{0}End", () => tracePrefix); + } - /// - /// Follows internal redirections through the umbracoInternalRedirectId document property. - /// - /// A value indicating whether redirection took place and led to a new published document. - /// - /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. - /// As per legacy, if the redirect does not work, we just ignore it. - /// - private bool FollowInternalRedirects() - { - const string tracePrefix = "FollowInternalRedirects: "; + /// + /// Follows internal redirections through the umbracoInternalRedirectId document property. + /// + /// A value indicating whether redirection took place and led to a new published document. + /// + /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. + /// As per legacy, if the redirect does not work, we just ignore it. + /// + private bool FollowInternalRedirects() + { + const string tracePrefix = "FollowInternalRedirects: "; + + if (_pcr.PublishedContent == null) + throw new InvalidOperationException("There is no PublishedContent."); - if (_pcr.PublishedContent == null) - throw new InvalidOperationException("There is no PublishedContent."); - // don't try to find a redirect if the property doesn't exist - if (_pcr.PublishedContent.HasProperty(Constants.Conventions.Content.InternalRedirectId) == false) - return false; + if (_pcr.PublishedContent.HasProperty(Constants.Conventions.Content.InternalRedirectId) == false) + return false; var redirect = false; - IPublishedContent internalRedirectNode = null; - var internalRedirectId = - _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId, -1); - var valueValid = false; - if (internalRedirectId > 0) - { - valueValid = true; - // Try and get the redirect node from a legacy integer ID - internalRedirectNode = _routingContext.UmbracoContext.ContentCache.GetById(internalRedirectId); - } - else - { - var udiInternalRedirectId = - _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId); + IPublishedContent internalRedirectNode = null; + var internalRedirectId = + _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId, -1); + var valueValid = false; + if (internalRedirectId > 0) + { + valueValid = true; + // Try and get the redirect node from a legacy integer ID + internalRedirectNode = _routingContext.UmbracoContext.ContentCache.GetById(internalRedirectId); + } + else + { + var udiInternalRedirectId = + _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId); if (udiInternalRedirectId != null) - { - valueValid = true; - // Try and get the redirect node from a UDI Guid - internalRedirectNode = - _routingContext.UmbracoContext.ContentCache.GetById(udiInternalRedirectId.Guid); - } - } + { + valueValid = true; + // Try and get the redirect node from a UDI Guid + internalRedirectNode = + _routingContext.UmbracoContext.ContentCache.GetById(udiInternalRedirectId.Guid); + } + } if (valueValid == false) - { + { // bad redirect - log and display the current page (legacy behavior) ProfilingLogger - .Logger.Debug( - "{0}Failed to redirect, value of '{1}' is not an int nor a GuidUdi", - () => tracePrefix, () => Constants.Conventions.Content.InternalRedirectId); - } + .Logger.Debug( + "{0}Failed to redirect, value of '{1}' is not an int nor a GuidUdi", + () => tracePrefix, () => Constants.Conventions.Content.InternalRedirectId); + } - if (internalRedirectNode == null) - { - ProfilingLogger.Logger.Debug( - "{0}Failed to redirect, value of '{1}' does not lead to a published document", () => tracePrefix, - () => Constants.Conventions.Content.InternalRedirectId); - } - else if (internalRedirectNode.Id == _pcr.PublishedContent.Id) - { - // redirect to self - ProfilingLogger.Logger.Debug("{0}Redirecting to self, ignore", - () => tracePrefix); - } - else - { - // Redirect to another page - _pcr.SetInternalRedirectPublishedContent(internalRedirectNode); - redirect = true; - ProfilingLogger.Logger.Debug("{0}Redirecting to id={1}", () => tracePrefix, - () => internalRedirectNode.Id); - } + if (internalRedirectNode == null) + { + ProfilingLogger.Logger.Debug( + "{0}Failed to redirect, value of '{1}' does not lead to a published document", () => tracePrefix, + () => Constants.Conventions.Content.InternalRedirectId); + } + else if (internalRedirectNode.Id == _pcr.PublishedContent.Id) + { + // redirect to self + ProfilingLogger.Logger.Debug("{0}Redirecting to self, ignore", + () => tracePrefix); + } + else + { + // Redirect to another page + _pcr.SetInternalRedirectPublishedContent(internalRedirectNode); + redirect = true; + ProfilingLogger.Logger.Debug("{0}Redirecting to id={1}", () => tracePrefix, + () => internalRedirectNode.Id); + } - return redirect; - } + return redirect; + } - /// - /// Ensures that access to current node is permitted. - /// - /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. - private void EnsurePublishedContentAccess() - { - const string tracePrefix = "EnsurePublishedContentAccess: "; + /// + /// Ensures that access to current node is permitted. + /// + /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. + private void EnsurePublishedContentAccess() + { + const string tracePrefix = "EnsurePublishedContentAccess: "; - if (_pcr.PublishedContent == null) - throw new InvalidOperationException("There is no PublishedContent."); + if (_pcr.PublishedContent == null) + throw new InvalidOperationException("There is no PublishedContent."); - var path = _pcr.PublishedContent.Path; + var path = _pcr.PublishedContent.Path; - var publicAccessAttempt = Services.PublicAccessService.IsProtected(path); + var publicAccessAttempt = Services.PublicAccessService.IsProtected(path); if (publicAccessAttempt) - { - ProfilingLogger.Logger.Debug("{0}Page is protected, check for access", () => tracePrefix); + { + ProfilingLogger.Logger.Debug("{0}Page is protected, check for access", () => tracePrefix); - var membershipHelper = new MembershipHelper(_routingContext.UmbracoContext); + var membershipHelper = new MembershipHelper(_routingContext.UmbracoContext); - if (membershipHelper.IsLoggedIn() == false) - { - ProfilingLogger.Logger.Debug("{0}Not logged in, redirect to login page", () => tracePrefix); + if (membershipHelper.IsLoggedIn() == false) + { + ProfilingLogger.Logger.Debug("{0}Not logged in, redirect to login page", () => tracePrefix); var loginPageId = publicAccessAttempt.Result.LoginNodeId; - if (loginPageId != _pcr.PublishedContent.Id) + if (loginPageId != _pcr.PublishedContent.Id) _pcr.PublishedContent = _routingContext.UmbracoContext.ContentCache.GetById(loginPageId); - } + } else if (Services.PublicAccessService.HasAccess(_pcr.PublishedContent.Id, Services.ContentService, _pcr.GetRolesForLogin(membershipHelper.CurrentUserName)) == false) - { - ProfilingLogger.Logger.Debug("{0}Current member has not access, redirect to error page", () => tracePrefix); - var errorPageId = publicAccessAttempt.Result.NoAccessNodeId; - if (errorPageId != _pcr.PublishedContent.Id) + { + ProfilingLogger.Logger.Debug("{0}Current member has not access, redirect to error page", () => tracePrefix); + var errorPageId = publicAccessAttempt.Result.NoAccessNodeId; + if (errorPageId != _pcr.PublishedContent.Id) _pcr.PublishedContent = _routingContext.UmbracoContext.ContentCache.GetById(errorPageId); - } - else - { - ProfilingLogger.Logger.Debug("{0}Current member has access", () => tracePrefix); - } - } - else - { - ProfilingLogger.Logger.Debug("{0}Page is not protected", () => tracePrefix); - } - } + } + else + { + // grab the current member + var member = membershipHelper.GetCurrentMember(); + // if the member has the "approved" and/or "locked out" properties, make sure they're correctly set before allowing access + var memberIsActive = true; + if (member != null) + { + if (member.HasProperty(Constants.Conventions.Member.IsApproved) == false) + memberIsActive = member.GetPropertyValue(Constants.Conventions.Member.IsApproved); - /// - /// Finds a template for the current node, if any. - /// - private void FindTemplate() - { - // NOTE: at the moment there is only 1 way to find a template, and then ppl must - // use the Prepared event to change the template if they wish. Should we also - // implement an ITemplateFinder logic? + if (member.HasProperty(Constants.Conventions.Member.IsLockedOut) == false) + memberIsActive = member.GetPropertyValue(Constants.Conventions.Member.IsLockedOut) == false; + } - const string tracePrefix = "FindTemplate: "; + if (memberIsActive == false) + { + ProfilingLogger.Logger.Debug("{0}Current member is either unapproved or locked out, redirect to error page", () => tracePrefix); + var errorPageId = publicAccessAttempt.Result.NoAccessNodeId; + if (errorPageId != _pcr.PublishedContent.Id) + _pcr.PublishedContent = _routingContext.UmbracoContext.ContentCache.GetById(errorPageId); + } + else + { + ProfilingLogger.Logger.Debug("{0}Current member has access", () => tracePrefix); + } + } + } + else + { + ProfilingLogger.Logger.Debug("{0}Page is not protected", () => tracePrefix); + } + } + + /// + /// Finds a template for the current node, if any. + /// + private void FindTemplate() + { + // NOTE: at the moment there is only 1 way to find a template, and then ppl must + // use the Prepared event to change the template if they wish. Should we also + // implement an ITemplateFinder logic? + + const string tracePrefix = "FindTemplate: "; if (_pcr.PublishedContent == null) { @@ -648,49 +671,49 @@ namespace Umbraco.Web.Routing return; } - // read the alternate template alias, from querystring, form, cookie or server vars, - // only if the published content is the initial once, else the alternate template - // does not apply + // read the alternate template alias, from querystring, form, cookie or server vars, + // only if the published content is the initial once, else the alternate template + // does not apply // + optionnally, apply the alternate template on internal redirects var useAltTemplate = _pcr.IsInitialPublishedContent || (_webRoutingSection.InternalRedirectPreservesTemplate && _pcr.IsInternalRedirectPublishedContent); string altTemplate = useAltTemplate ? _routingContext.UmbracoContext.HttpContext.Request[Constants.Conventions.Url.AltTemplate] - : null; + : null; - if (string.IsNullOrWhiteSpace(altTemplate)) - { - // we don't have an alternate template specified. use the current one if there's one already, - // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...), - // else lookup the template id on the document then lookup the template with that id. + if (string.IsNullOrWhiteSpace(altTemplate)) + { + // we don't have an alternate template specified. use the current one if there's one already, + // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...), + // else lookup the template id on the document then lookup the template with that id. - if (_pcr.HasTemplate) - { - ProfilingLogger.Logger.Debug("{0}Has a template already, and no alternate template.", () => tracePrefix); - return; - } + if (_pcr.HasTemplate) + { + ProfilingLogger.Logger.Debug("{0}Has a template already, and no alternate template.", () => tracePrefix); + return; + } - // TODO: When we remove the need for a database for templates, then this id should be irrelavent, - // not sure how were going to do this nicely. + // TODO: When we remove the need for a database for templates, then this id should be irrelavent, + // not sure how were going to do this nicely. - var templateId = _pcr.PublishedContent.TemplateId; + var templateId = _pcr.PublishedContent.TemplateId; // This code was moved to GetTemplateModel to allow the same functionality on a failed altTemplate (U4-8550) // The only change is a diffent logger prefix and null will be set to _pcr.TemplateModel if the templateId is <= 0 // rather than no set taking place _pcr.TemplateModel = GetTemplateModel(_pcr.PublishedContent.TemplateId); } - else - { - // we have an alternate template specified. lookup the template with that alias - // this means the we override any template that a content lookup might have set - // so /path/to/page/template1?altTemplate=template2 will use template2 + else + { + // we have an alternate template specified. lookup the template with that alias + // this means the we override any template that a content lookup might have set + // so /path/to/page/template1?altTemplate=template2 will use template2 - // ignore if the alias does not match - just trace + // ignore if the alias does not match - just trace - if (_pcr.HasTemplate) - ProfilingLogger.Logger.Debug("{0}Has a template already, but also an alternate template.", () => tracePrefix); - ProfilingLogger.Logger.Debug("{0}Look for alternate template alias=\"{1}\"", () => tracePrefix, () => altTemplate); + if (_pcr.HasTemplate) + ProfilingLogger.Logger.Debug("{0}Has a template already, but also an alternate template.", () => tracePrefix); + ProfilingLogger.Logger.Debug("{0}Look for alternate template alias=\"{1}\"", () => tracePrefix, () => altTemplate); if (_pcr.PublishedContent.IsAllowedTemplate(altTemplate)) { @@ -705,26 +728,26 @@ namespace Umbraco.Web.Routing LogHelper.Warn("{0}Configuration settings prevent template \"{1}\" from showing for node \"{2}\"", () => tracePrefix, () => altTemplate, () => _pcr.PublishedContent.Id); _pcr.TemplateModel = GetTemplateModel(_pcr.PublishedContent.TemplateId); } - } + } - if (_pcr.HasTemplate == false) - { - ProfilingLogger.Logger.Debug("{0}No template was found.", () => tracePrefix); + if (_pcr.HasTemplate == false) + { + ProfilingLogger.Logger.Debug("{0}No template was found.", () => tracePrefix); - // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true - // then reset _pcr.Document to null to force a 404. - // - // but: because we want to let MVC hijack routes even though no template is defined, we decide that - // a missing template is OK but the request will then be forwarded to MVC, which will need to take - // care of everything. - // - // so, don't set _pcr.Document to null here - } - else - { - ProfilingLogger.Logger.Debug("{0}Running with template id={1} alias=\"{2}\"", () => tracePrefix, () => _pcr.TemplateModel.Id, () => _pcr.TemplateModel.Alias); - } - } + // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true + // then reset _pcr.Document to null to force a 404. + // + // but: because we want to let MVC hijack routes even though no template is defined, we decide that + // a missing template is OK but the request will then be forwarded to MVC, which will need to take + // care of everything. + // + // so, don't set _pcr.Document to null here + } + else + { + ProfilingLogger.Logger.Debug("{0}Running with template id={1} alias=\"{2}\"", () => tracePrefix, () => _pcr.TemplateModel.Id, () => _pcr.TemplateModel.Alias); + } + } private ITemplate GetTemplateModel(int templateId) { @@ -751,32 +774,32 @@ namespace Umbraco.Web.Routing /// /// As per legacy, if the redirect does not work, we just ignore it. private void FollowExternalRedirect() - { - if (_pcr.HasPublishedContent == false) return; + { + if (_pcr.HasPublishedContent == false) return; - // don't try to find a redirect if the property doesn't exist + // don't try to find a redirect if the property doesn't exist if (_pcr.PublishedContent.HasProperty(Constants.Conventions.Content.Redirect) == false) - return; - - var redirectId = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect, -1); + return; - var redirectUrl = "#"; - if (redirectId > 0) - { - redirectUrl = _routingContext.UrlProvider.GetUrl(redirectId); - } - else - { + var redirectId = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect, -1); + + var redirectUrl = "#"; + if (redirectId > 0) + { + redirectUrl = _routingContext.UrlProvider.GetUrl(redirectId); + } + else + { // might be a UDI instead of an int Id - var redirectUdi = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect); - if (redirectUdi != null) - redirectUrl = _routingContext.UrlProvider.GetUrl(redirectUdi.Guid); - } - if (redirectUrl != "#") - { - _pcr.SetRedirect(redirectUrl); - } - } - #endregion - } + var redirectUdi = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect); + if (redirectUdi != null) + redirectUrl = _routingContext.UrlProvider.GetUrl(redirectUdi.Guid); + } + if (redirectUrl != "#") + { + _pcr.SetRedirect(redirectUrl); + } + } + #endregion + } } From b9430158cedb0bf5b1c0b93f543ec5383d8bec41 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 14 Jan 2019 09:25:59 +0100 Subject: [PATCH 081/223] Move member group picker property data store from NVarchar to NText (#3712) --- .../UpdateMemberGroupPickerData.cs | 36 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../MemberGroupPickerPropertyEditor.cs | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs new file mode 100644 index 0000000000..2dbc69e58a --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs @@ -0,0 +1,36 @@ +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourteenZero +{ + /// + /// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268. + /// + [Migration("7.14.0", 1, Constants.System.UmbracoMigrationName)] + public class UpdateMemberGroupPickerData : MigrationBase + { + public UpdateMemberGroupPickerData(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger) + { + } + + public override void Up() + { + // move the data for all member group properties from the NVarchar to the NText column and clear the NVarchar column + Execute.Sql(@"UPDATE cmsPropertyData SET dataNtext = dataNvarchar, dataNvarchar = NULL + WHERE dataNtext IS NULL AND id IN ( + SELECT id FROM cmsPropertyData WHERE propertyTypeId in ( + SELECT id from cmsPropertyType where dataTypeID IN ( + SELECT nodeId FROM cmsDataType WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker' + ) + ) + )"); + + // ensure that all exising member group properties are defined as NText + Execute.Sql("UPDATE cmsDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker'"); + } + + public override void Down() + { + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index c7393e524f..8ee29e777f 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -572,6 +572,7 @@ + diff --git a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs index 433199c536..6d7dd9e344 100644 --- a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", "membergrouppicker", Group="People", Icon="icon-users")] + [PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", PropertyEditorValueTypes.Text, "membergrouppicker", Group="People", Icon="icon-users")] public class MemberGroupPickerPropertyEditor : PropertyEditor { } From 2ce3249c5e99fc27656f2af84b014bec937ea412 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 14 Jan 2019 13:23:00 +0100 Subject: [PATCH 082/223] Renaming variable to allow MNTP media selection --- .../src/common/services/tinymce.service.js | 2 +- .../linkpicker/linkpicker.controller.js | 2 +- .../mediapicker/mediapicker.controller.js | 24 +++++++++---------- .../prevalueeditors/imagepicker.controller.js | 2 +- .../grid/editors/media.controller.js | 2 +- .../markdowneditor.controller.js | 2 +- .../mediapicker/mediapicker.controller.js | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 3fc11f8225..97d939bac1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -1316,7 +1316,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0], startNodeIsVirtual: userData.startMediaIds.length !== 1, submit: function (model) { - self.insertMediaInEditor(args.editor, model.selectedImages[0]); + self.insertMediaInEditor(args.editor, model.selection[0]); editorService.close(); }, close: function () { diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js index 81dfcfd5d3..4faa5fd03a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js @@ -118,7 +118,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController", startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0], startNodeIsVirtual: userData.startMediaIds.length !== 1, submit: function (model) { - var media = model.selectedImages[0]; + var media = model.selection[0]; $scope.model.target.id = media.id; $scope.model.target.udi = media.udi; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js index a274c25287..7b3d13937f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js @@ -41,7 +41,7 @@ angular.module("umbraco") $scope.maxFileSize = umbracoSettings.maxFileSize + "KB"; - $scope.model.selectedImages = []; + $scope.model.selection = []; $scope.acceptedMediatypes = []; mediaTypeHelper.getAllowedImagetypes($scope.startNodeId) @@ -145,7 +145,7 @@ angular.module("umbraco") $scope.gotoFolder = function(folder) { if (!$scope.multiPicker) { - deselectAllImages($scope.model.selectedImages); + deselectAllImages($scope.model.selection); } if (!folder) { @@ -212,19 +212,19 @@ angular.module("umbraco") function selectImage(image) { if (image.selected) { - for (var i = 0; $scope.model.selectedImages.length > i; i++) { - var imageInSelection = $scope.model.selectedImages[i]; + for (var i = 0; $scope.model.selection.length > i; i++) { + var imageInSelection = $scope.model.selection[i]; if (image.key === imageInSelection.key) { image.selected = false; - $scope.model.selectedImages.splice(i, 1); + $scope.model.selection.splice(i, 1); } } } else { if (!$scope.multiPicker) { - deselectAllImages($scope.model.selectedImages); + deselectAllImages($scope.model.selection); } image.selected = true; - $scope.model.selectedImages.push(image); + $scope.model.selection.push(image); } } @@ -238,7 +238,7 @@ angular.module("umbraco") $scope.onUploadComplete = function(files) { $scope.gotoFolder($scope.currentFolder).then(function() { - if (files.length === 1 && $scope.model.selectedImages.length === 0) { + if (files.length === 1 && $scope.model.selection.length === 0) { var image = $scope.images[$scope.images.length - 1]; $scope.target = image; $scope.target.url = mediaHelper.resolveFile(image); @@ -275,7 +275,7 @@ angular.module("umbraco") $scope.mediaPickerDetailsOverlay.show = true; $scope.mediaPickerDetailsOverlay.submit = function(model) { - $scope.model.selectedImages.push($scope.target); + $scope.model.selection.push($scope.target); $scope.model.submit($scope.model); $scope.mediaPickerDetailsOverlay.show = false; @@ -384,11 +384,11 @@ angular.module("umbraco") var folderImage = $scope.images[folderImageIndex]; var imageIsSelected = false; - if ($scope.model && angular.isArray($scope.model.selectedImages)) { + if ($scope.model && angular.isArray($scope.model.selection)) { for (var selectedImageIndex = 0; - selectedImageIndex < $scope.model.selectedImages.length; + selectedImageIndex < $scope.model.selection.length; selectedImageIndex++) { - var selectedImage = $scope.model.selectedImages[selectedImageIndex]; + var selectedImage = $scope.model.selection[selectedImageIndex]; if (folderImage.key === selectedImage.key) { imageIsSelected = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js index 6e7071a7e4..fc3da3510e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js @@ -7,7 +7,7 @@ function imageFilePickerController($scope) { onlyImages: true, show: true, submit: function (model) { - $scope.model.value = model.selectedImages[0].image; + $scope.model.value = model.selection[0].image; $scope.mediaPickerOverlay.show = false; $scope.mediaPickerOverlay = null; }, diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js index c240d6b37d..e267133cf4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js @@ -27,7 +27,7 @@ angular.module("umbraco") disableFolderSelect: true, onlyImages: true, submit: function(model) { - var selectedImage = model.selectedImages[0]; + var selectedImage = model.selection[0]; $scope.control.value = { focalPoint: selectedImage.focalPoint, diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js index b3c014f54a..67a5630909 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js @@ -16,7 +16,7 @@ function MarkdownEditorController($scope, $element, assetsService, editorService var mediaPicker = { disableFolderSelect: true, submit: function(model) { - var selectedImagePath = model.selectedImages[0].image; + var selectedImagePath = model.selection[0].image; callback(selectedImagePath); editorService.close(); }, diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js index 361354c524..bac8eb903a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js @@ -176,7 +176,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl editorService.close(); - _.each(model.selectedImages, function (media, i) { + _.each(model.selection, function (media, i) { // if there is no thumbnail, try getting one if the media is not a placeholder item if (!media.thumbnail && media.id && media.metaData) { media.thumbnail = mediaHelper.resolveFileFromEntity(media, true); From 1ac8bbc570ab4a3a9d7f5ee24c66f0ad8a5dee85 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 14 Jan 2019 13:23:57 +0100 Subject: [PATCH 083/223] Fixes MNTP member selection tree --- .../propertyeditors/contentpicker/contentpicker.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index e084d7116a..b72d81f16d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -222,7 +222,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper editorService.mediaPicker($scope.currentPicker); break; case "Member": - editorService.memberGroupPicker($scope.currentPicker); + editorService.treePicker($scope.currentPicker); break; default: From 8e4090fb84d40b8aa3efa3d45119b4c8e3fa9692 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 14 Jan 2019 14:00:17 +0100 Subject: [PATCH 084/223] Added proper memberPicker in the editorService --- .../src/common/services/editor.service.js | 26 ++++++++++++++++++- .../contentpicker/contentpicker.controller.js | 2 +- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index 0d6432b01f..6cdb8fd0f3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -748,6 +748,29 @@ When building a custom infinite editor view you can use the same components as a open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#memberPicker + * @methodOf umbraco.services.editorService + * + * @description + * Opens a member picker in infinite editing, the submit callback returns an array of selected items + * + * @param {Object} editor rendering options + * @param {Boolean} editor.multiPicker Pick one or multiple items + * @param {Function} editor.submit Callback function when the submit button is clicked. Returns the editor model object + * @param {Function} editor.close Callback function when the close button is clicked. + * + * @returns {Object} editor object + */ + function memberPicker(editor) { + editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; + editor.size = "small"; + editor.section = "member"; + editor.treeAlias = "member"; + open(editor); + } + /////////////////////// /** @@ -824,7 +847,8 @@ When building a custom infinite editor view you can use the same components as a userPicker: userPicker, itemPicker: itemPicker, macroPicker: macroPicker, - memberGroupPicker: memberGroupPicker + memberGroupPicker: memberGroupPicker, + memberPicker: memberPicker }; return service; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index b72d81f16d..37a97e928c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -222,7 +222,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper editorService.mediaPicker($scope.currentPicker); break; case "Member": - editorService.treePicker($scope.currentPicker); + editorService.memberPicker($scope.currentPicker); break; default: From 4ad2505bea438f3e0d35c02cce350d7d58c13d93 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 14 Jan 2019 15:48:24 +0100 Subject: [PATCH 085/223] Identify element types --- .../Migrations/Upgrade/UmbracoPlan.cs | 1 + .../V_8_0_0/AddContentTypeIsElementColumn.cs | 15 ++++++++++ src/Umbraco.Core/Models/ContentTypeBase.cs | 10 +++++++ .../Models/ContentTypeBaseExtensions.cs | 3 +- src/Umbraco.Core/Models/IContentTypeBase.cs | 12 +++++++- .../PublishedContent/PublishedItemType.cs | 7 ++++- .../Persistence/Dtos/ContentTypeDto.cs | 4 +++ .../Factories/ContentTypeFactory.cs | 2 ++ .../Persistence/Mappers/ContentTypeMapper.cs | 1 + .../Persistence/Mappers/MediaTypeMapper.cs | 1 + .../Persistence/Mappers/MemberTypeMapper.cs | 1 + .../Implement/ContentTypeRepositoryBase.cs | 6 ++-- .../Services/EntityXmlSerializer.cs | 3 +- .../Services/Implement/PackagingService.cs | 4 +++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../PublishedContent/PublishedContentTests.cs | 1 - .../Services/ContentTypeServiceTests.cs | 30 +++++++++++++++++++ .../ContentEditing/ContentItemDisplay.cs | 8 ++++- .../Models/Mapping/ContentMapperProfile.cs | 5 ++-- 19 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index b469c02a3c..9ec970f1fe 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -121,6 +121,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{648A2D5F-7467-48F8-B309-E99CEEE00E2A}"); // fixed version To("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}"); To("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}"); + To("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}"); //FINAL diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs new file mode 100644 index 0000000000..1df11a3e99 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs @@ -0,0 +1,15 @@ +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class AddContentTypeIsElementColumn : MigrationBase + { + public AddContentTypeIsElementColumn(IMigrationContext context) : base(context) + { } + + public override void Migrate() + { + AddColumn("isElement"); + } + } +} diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 88b1179f6d..b6ea9f50a0 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -26,6 +26,7 @@ namespace Umbraco.Core.Models private string _thumbnail = "folder.png"; private bool _allowedAsRoot; // note: only one that's not 'pure element type' private bool _isContainer; + private bool _isElement; private PropertyGroupCollection _propertyGroups; private PropertyTypeCollection _noGroupPropertyTypes; private IEnumerable _allowedContentTypes; @@ -90,6 +91,7 @@ namespace Umbraco.Core.Models public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon); public readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.Thumbnail); public readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot); + public readonly PropertyInfo IsElementSelector = ExpressionHelper.GetPropertyInfo(x => x.IsElement); public readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer); public readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes); public readonly PropertyInfo PropertyGroupsSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups); @@ -180,6 +182,14 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _isContainer, Ps.Value.IsContainerSelector); } + /// + [DataMember] + public bool IsElement + { + get => _isElement; + set => SetPropertyValueAndDetectChanges(value, ref _isElement, Ps.Value.IsElementSelector); + } + /// /// Gets or sets a list of integer Ids for allowed ContentTypes /// diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs index 8af48bb881..adbc3de54f 100644 --- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs @@ -15,7 +15,8 @@ namespace Umbraco.Core.Models { var type = contentType.GetType(); var itemType = PublishedItemType.Unknown; - if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content; + if (contentType.IsElement) itemType = PublishedItemType.Element; + else if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content; else if (typeof(IMediaType).IsAssignableFrom(type)) itemType = PublishedItemType.Media; else if (typeof(IMemberType).IsAssignableFrom(type)) itemType = PublishedItemType.Member; return itemType; diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index a1d4aee02f..787e347b37 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Models /// the icon (eg. icon-home) along with an optional CSS class name representing the /// color (eg. icon-blue). Put together, the value for this scenario would be /// icon-home color-blue. - /// + /// /// If a class name for the color isn't specified, the icon color will default to black. /// string Icon { get; set; } @@ -48,6 +48,16 @@ namespace Umbraco.Core.Models /// bool IsContainer { get; set; } + /// + /// Gets or sets a value indicating whether this content type is for an element. + /// + /// + /// By default a content type is for a true media, member or document, but + /// it can also be for an element, ie a subset that can for instance be used in + /// nested content. + /// + bool IsElement { get; set; } + /// /// Gets or sets the content variation of the content type. /// diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs index e55fe66945..42e9c9538d 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs @@ -4,13 +4,18 @@ /// The type of published element. ///
/// Can be a simple element, or a document, a media, a member. - public enum PublishedItemType // fixme - need to rename to PublishedElementType but then conflicts? + public enum PublishedItemType { /// /// Unknown. /// Unknown = 0, + /// + /// An element. + /// + Element, + /// /// A document. /// diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs index d930abc54c..4f3a67aa91 100644 --- a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs @@ -41,6 +41,10 @@ namespace Umbraco.Core.Persistence.Dtos [Constraint(Default = "0")] public bool IsContainer { get; set; } + [Column("isElement")] + [Constraint(Default = "0")] + public bool IsElement { get; set; } + [Column("allowAtRoot")] [Constraint(Default = "0")] public bool AllowAtRoot { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs index 38a1aa2aab..7a04a6d0d9 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs @@ -107,6 +107,7 @@ namespace Umbraco.Core.Persistence.Factories entity.CreatorId = dto.NodeDto.UserId ?? Constants.Security.UnknownUserId; entity.AllowedAsRoot = dto.AllowAtRoot; entity.IsContainer = dto.IsContainer; + entity.IsElement = dto.IsElement; entity.Trashed = dto.NodeDto.Trashed; entity.Variations = (ContentVariation) dto.Variations; } @@ -132,6 +133,7 @@ namespace Umbraco.Core.Persistence.Factories NodeId = entity.Id, AllowAtRoot = entity.AllowedAsRoot, IsContainer = entity.IsContainer, + IsElement = entity.IsElement, Variations = (byte) entity.Variations, NodeDto = BuildNodeDto(entity, nodeObjectType) }; diff --git a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs index c692a75474..a24963bace 100644 --- a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs @@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs index 3f5a6e24bc..6cf83bc7aa 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs @@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs index 28dc19171f..9a4e4ec040 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs @@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 662254d1ee..683df047f8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1283,7 +1283,7 @@ AND umbracoNode.id <> @id", if (db == null) throw new ArgumentNullException(nameof(db)); var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations, - cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey, umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, @@ -1384,6 +1384,7 @@ AND umbracoNode.id <> @id", Description = currCt.ctDesc, Icon = currCt.ctIcon, IsContainer = currCt.ctIsContainer, + IsElement = currCt.ctIsElement, NodeId = currCt.ctId, PrimaryKey = currCt.ctPk, Thumbnail = currCt.ctThumb, @@ -1422,7 +1423,7 @@ AND umbracoNode.id <> @id", var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId, cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations, - cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey, umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, @@ -1559,6 +1560,7 @@ AND umbracoNode.id <> @id", Description = currCt.ctDesc, Icon = currCt.ctIcon, IsContainer = currCt.ctIsContainer, + IsElement = currCt.ctIsElement, NodeId = currCt.ctId, PrimaryKey = currCt.ctPk, Thumbnail = currCt.ctThumb, diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index d938e032a8..38d5471bb7 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -337,7 +337,8 @@ namespace Umbraco.Core.Services new XElement("Thumbnail", contentType.Thumbnail), new XElement("Description", contentType.Description), new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()), - new XElement("IsListView", contentType.IsContainer.ToString())); + new XElement("IsListView", contentType.IsContainer.ToString()), + new XElement("IsElement", contentType.IsElement.ToString())); var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId); if(masterContentType != null) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 106d2b9f12..8f6c287cf1 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -578,6 +578,10 @@ namespace Umbraco.Core.Services.Implement if (isListView != null) contentType.IsContainer = isListView.Value.InvariantEquals("true"); + var isElement = infoElement.Element("IsElement"); + if (isListView != null) + contentType.IsElement = isElement.Value.InvariantEquals("true"); + //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set var masterElement = infoElement.Element("Master"); if (masterElement != null) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index a01bbf1746..33858c0f91 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -375,6 +375,7 @@ + diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 914956dce1..ab65ac82b1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -233,7 +233,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("Fails as long as PublishedContentModel is internal.")] // fixme public void Is_Last_From_Where_Filter2() { var doc = GetNode(1173); diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index b1a8fa26a8..8dc8a2b45c 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -22,6 +22,36 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] public class ContentTypeServiceTests : TestWithSomeContentBase { + [Test] + public void CanSaveAndGetIsElement() + { + //create content type with a property type that varies by culture + IContentType contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Nothing; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Nothing + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + ServiceContext.ContentTypeService.Save(contentType); + + contentType = ServiceContext.ContentTypeService.Get(contentType.Id); + Assert.IsFalse(contentType.IsElement); + + contentType.IsElement = true; + ServiceContext.ContentTypeService.Save(contentType); + + contentType = ServiceContext.ContentTypeService.Get(contentType.Id); + Assert.IsTrue(contentType.IsElement); + } + [Test] public void Change_Content_Type_Variation_Clears_Redirects() { diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index 4908025351..80358bfc7a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -86,6 +86,12 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } + /// + /// Indicates if the content is configured as an element + /// + [DataMember(Name = "isElement")] + public bool IsElement { get; set; } + /// /// Property indicating if this item is part of a list view parent /// @@ -117,7 +123,7 @@ namespace Umbraco.Web.Models.ContentEditing /// [DataMember(Name = "updateDate")] public DateTime UpdateDate { get; set; } - + [DataMember(Name = "template")] public string TemplateAlias { get; set; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs index 6de3bdc02c..1caf81a1eb 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs @@ -46,6 +46,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name)) .ForMember(dest => dest.IsContainer, opt => opt.MapFrom(src => src.ContentType.IsContainer)) + .ForMember(dest => dest.IsElement, opt => opt.MapFrom(src => src.ContentType.IsElement)) .ForMember(dest => dest.IsBlueprint, opt => opt.MapFrom(src => src.Blueprint)) .ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) @@ -59,7 +60,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.AllowedTemplates, opt => opt.MapFrom(content => content.ContentType.AllowedTemplates .Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false) - .ToDictionary(t => t.Alias, t => t.Name))) + .ToDictionary(t => t.Alias, t => t.Name))) .ForMember(dest => dest.AllowedActions, opt => opt.ResolveUsing(src => actionButtonsResolver.Resolve(src))) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); @@ -140,5 +141,5 @@ namespace Umbraco.Web.Models.Mapping return source.CultureInfos.TryGetValue(culture, out var name) && !name.Name.IsNullOrWhiteSpace() ? name.Name : $"(({source.Name}))"; } } - } + } } From f7671ec9a7653082d432352a7801e5bedb621c5c Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 15 Jan 2019 08:39:43 +0100 Subject: [PATCH 086/223] Fixes #4071 - Error executing scheduled task - This instance has already started one or more requests. --- src/Umbraco.Web/Scheduling/ScheduledTasks.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs index 4278b82c34..7387bca000 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs @@ -63,10 +63,11 @@ namespace Umbraco.Web.Scheduling private async Task GetTaskByHttpAync(string url, CancellationToken token) { if (_httpClient == null) - _httpClient = new HttpClient(); - - if (Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri)) - _httpClient.BaseAddress = baseUri; + { + _httpClient = Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri) + ? new HttpClient { BaseAddress = baseUri } + : new HttpClient(); + } var request = new HttpRequestMessage(HttpMethod.Get, url); From 64469fcb5c72074cb9f410687ca90329db63d6b1 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 15 Jan 2019 10:03:10 +0100 Subject: [PATCH 087/223] Force select the content app for both views when opening split view --- .../content/umbvariantcontenteditors.directive.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js index 1987c897f0..e413701a26 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js @@ -215,9 +215,15 @@ * @param {any} selectedVariant */ function openSplitView(selectedVariant) { - var selectedCulture = selectedVariant.language.culture; + //Find the whole variant model based on the culture that was chosen + var variant = _.find(vm.content.variants, function (v) { + return v.language.culture === selectedCulture; + }); + + insertVariantEditor(vm.editors.length, initVariant(variant, vm.editors.length)); + //only the content app can be selected since no other apps are shown, and because we copy all of these apps //to the "editors" we need to update this across all editors for (var e = 0; e < vm.editors.length; e++) { @@ -233,13 +239,6 @@ } } - //Find the whole variant model based on the culture that was chosen - var variant = _.find(vm.content.variants, function (v) { - return v.language.culture === selectedCulture; - }); - - insertVariantEditor(vm.editors.length, initVariant(variant, vm.editors.length)); - //TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular editor.collapsed = true; editor.loading = true; From 9bc047c03f50e4795fc0d13b71af8218889d1e5a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 15 Jan 2019 10:17:26 +0100 Subject: [PATCH 088/223] Adding code to re-validate on value change --- .../directives/components/tags/umbtagseditor.directive.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index fea7528d5b..125f5ffb65 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -182,6 +182,9 @@ else { vm.onValueChanged({ value: [] }); } + + //this is required to re-validate + $scope.propertyForm.tagCount.$setViewValue($scope.model.value.length); } /** @@ -189,7 +192,7 @@ */ function validateMandatory() { return { - isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0) || (vm.value != null && vm.value.length > 0), + isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0), errorMsg: "Value cannot be empty", errorKey: "required" }; From 0092cac394037f1ec2696718954e6e4be4f1d90a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 15 Jan 2019 10:31:12 +0100 Subject: [PATCH 089/223] DRY --- .../components/tags/umbtagseditor.directive.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index 125f5ffb65..92c9d57ee8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -130,8 +130,7 @@ if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) { configureViewModel(); - //this is required to re-validate - vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length); + reValidate() } } @@ -183,8 +182,7 @@ vm.onValueChanged({ value: [] }); } - //this is required to re-validate - $scope.propertyForm.tagCount.$setViewValue($scope.model.value.length); + reValidate(); } /** @@ -273,8 +271,12 @@ return ($.inArray(suggestion.value, vm.viewModel) === -1); }); } - - + + function reValidate() { + //this is required to re-validate + vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length); + { + } })(); From ba38b67b9d4cdd58d33a729b62181700b3d51dbe Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 11:30:30 +0100 Subject: [PATCH 090/223] Support IContentType.IsElement --- .../services/umbdataformatter.service.js | 18 +++++++-------- .../permissions/permissions.controller.js | 22 +++++++------------ .../views/permissions/permissions.html | 20 +++++++++++++++-- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 ++ .../Umbraco/config/lang/en_us.xml | 2 ++ .../ContentTypeCompositionDisplay.cs | 4 ++++ .../Models/ContentEditing/ContentTypeSave.cs | 3 +++ 7 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index e31742e660..1e6fc5d643 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -64,7 +64,7 @@ var saveModel = _.pick(displayModel, 'compositeContentTypes', 'isContainer', 'allowAsRoot', 'allowedTemplates', 'allowedContentTypes', 'alias', 'description', 'thumbnail', 'name', 'id', 'icon', 'trashed', - 'key', 'parentId', 'alias', 'path', 'allowCultureVariant'); + 'key', 'parentId', 'alias', 'path', 'allowCultureVariant', 'isElement'); //TODO: Map these saveModel.allowedTemplates = _.map(displayModel.allowedTemplates, function (t) { return t.alias; }); @@ -262,7 +262,7 @@ saveModel[props[m]] = startId.id; } - saveModel.parentId = -1; + saveModel.parentId = -1; return saveModel; }, @@ -293,7 +293,7 @@ }); saveModel.email = propEmail.value.trim(); saveModel.username = propLogin.value.trim(); - + saveModel.password = this.formatChangePasswordModel(propPass.value); var selectedGroups = []; @@ -336,7 +336,7 @@ /** formats the display model used to display the media to the model used to save the media */ formatMediaPostData: function (displayModel, action) { - //NOTE: the display model inherits from the save model so we can in theory just post up the display model but + //NOTE: the display model inherits from the save model so we can in theory just post up the display model but // we don't want to post all of the data as it is unecessary. var saveModel = { id: displayModel.id, @@ -354,7 +354,7 @@ /** formats the display model used to display the content to the model used to save the content */ formatContentPostData: function (displayModel, action) { - //NOTE: the display model inherits from the save model so we can in theory just post up the display model but + //NOTE: the display model inherits from the save model so we can in theory just post up the display model but // we don't want to post all of the data as it is unecessary. var saveModel = { id: displayModel.id, @@ -379,7 +379,7 @@ var propExpireDate = displayModel.removeDate; var propReleaseDate = displayModel.releaseDate; var propTemplate = displayModel.template; - + saveModel.expireDate = propExpireDate ? propExpireDate : null; saveModel.releaseDate = propReleaseDate ? propReleaseDate : null; saveModel.templateAlias = propTemplate ? propTemplate : null; @@ -389,8 +389,8 @@ /** * This formats the server GET response for a content display item - * @param {} displayModel - * @returns {} + * @param {} displayModel + * @returns {} */ formatContentGetData: function(displayModel) { @@ -418,7 +418,7 @@ } }); }); - + //now assign this same invariant property instance to the same index of the other variants property array for (var j = 1; j < displayModel.variants.length; j++) { diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js index 4a7a870618..317fe094ae 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js @@ -25,6 +25,7 @@ vm.removeChild = removeChild; vm.toggleAllowAsRoot = toggleAllowAsRoot; vm.toggleAllowCultureVariants = toggleAllowCultureVariants; + vm.toggleIsElement = toggleIsElement; /* ---------- INIT ---------- */ @@ -84,25 +85,18 @@ $scope.model.allowedContentTypes.splice(selectedChildIndex, 1); } - /** - * Toggle the $scope.model.allowAsRoot value to either true or false - */ - function toggleAllowAsRoot(){ - if($scope.model.allowAsRoot){ - $scope.model.allowAsRoot = false; - return; - } + // note: "safe toggling" here ie handling cases where the value is undefined, etc - $scope.model.allowAsRoot = true; + function toggleAllowAsRoot() { + $scope.model.allowAsRoot = $scope.model.allowAsRoot ? false : true; } function toggleAllowCultureVariants() { - if ($scope.model.allowCultureVariant) { - $scope.model.allowCultureVariant = false; - return; - } + $scope.model.allowCultureVariant = $scope.model.allowCultureVariant ? false : true; + } - $scope.model.allowCultureVariant = true; + function toggleIsElement() { + $scope.model.isElement = $scope.model.isElement ? false : true; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html index ec1e528f8c..0d74c655d7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html @@ -53,9 +53,25 @@ hotkey="alt+shift+v"> - + - +
+ +
+
+ +
+ +
+ + +
+ +
+ + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 386d3af518..987203442a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1518,6 +1518,8 @@ To manage your website, simply open the Umbraco back office and start adding con Allow varying by culture Allow editors to create content of this type in different languages Allow varying by culture + Is an Element type + An Element type is meant to be used for instance in Nested Content, and not in the tree Building models 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 5de373f571..1860d3afc9 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1559,6 +1559,8 @@ To manage your website, simply open the Umbraco back office and start adding con Allow varying by culture Allow editors to create content of this type in different languages Allow varying by culture + Is an Element type + An Element type is meant to be used for instance in Nested Content, and not in the tree Add language diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs index 7211ddbf61..e5e74c2749 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs @@ -26,6 +26,10 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } + //Element + [DataMember(Name = "isElement")] + public bool IsElement { get; set; } + [DataMember(Name = "listViewEditorName")] [ReadOnly(true)] public string ListViewEditorName { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs index c2ec70d3dc..b1d24c5fd2 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs @@ -25,6 +25,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } + [DataMember(Name = "isElement")] + public bool IsElement { get; set; } + [DataMember(Name = "allowAsRoot")] public bool AllowAsRoot { get; set; } From 44ab0991ceaa653befbd0eede1277902d047fff0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 15 Jan 2019 22:08:08 +1100 Subject: [PATCH 091/223] Package installing is working --- .../Composing/Composers/ServicesComposer.cs | 1 - src/Umbraco.Core/Composing/TypeLoader.cs | 2 +- src/Umbraco.Core/IO/IOHelper.cs | 54 --- src/Umbraco.Core/IO/ShadowWrapper.cs | 2 +- src/Umbraco.Core/IO/SystemDirectories.cs | 4 + .../Models/Packaging/CompiledPackage.cs | 3 +- .../Models/Packaging/InstallationSummary.cs | 2 +- .../Models/Packaging/PackageDefinition.cs | 3 + .../Models/Packaging/UninstallationSummary.cs | 6 +- .../Packaging/CompiledPackageXmlParser.cs | 4 +- .../Packaging/IPackageActionRunner.cs | 11 +- .../Packaging/IPackageInstallation.cs | 13 +- .../Packaging/PackageActionRunner.cs | 29 +- .../Packaging/PackageDataInstallation.cs | 127 ++++++- .../Packaging/PackageDefinitionXmlParser.cs | 2 +- .../Packaging/PackageFileInstallation.cs | 26 ++ .../Packaging/PackageInstallation.cs | 77 ++-- .../Packaging/PackagesRepository.cs | 2 +- .../Services/IPackagingService.cs | 16 +- .../Services/Implement/PackagingService.cs | 48 +-- .../Sync/DatabaseServerMessenger.cs | 2 +- src/Umbraco.Examine/LuceneIndexCreator.cs | 2 +- .../Composing/TypeLoaderTests.cs | 2 +- src/Umbraco.Tests/IO/ShadowFileSystemTests.cs | 8 +- .../Packaging/PackageInstallationTest.cs | 20 +- .../Scoping/ScopeFileSystemsTests.cs | 2 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 3 +- .../src/views/packages/edit.controller.js | 2 + .../src/views/packages/edit.html | 2 +- .../views/install-local.controller.js | 131 ++++--- .../Binders/ContentModelBinderHelper.cs | 3 +- .../Editors/ContentTypeController.cs | 19 +- src/Umbraco.Web/Editors/MediaController.cs | 2 +- src/Umbraco.Web/Editors/PackageController.cs | 2 +- .../Editors/PackageInstallController.cs | 258 +++---------- src/Umbraco.Web/Editors/UsersController.cs | 2 +- .../Controllers/InstallPackageController.cs | 346 +++++++++--------- src/Umbraco.Web/Install/InstallHelper.cs | 25 -- .../Install/InstallStatusTracker.cs | 4 +- .../InstallSteps/StarterKitDownloadStep.cs | 24 +- .../InstallSteps/StarterKitInstallStep.cs | 10 +- .../Models/ContentTypeImportModel.cs | 12 +- .../Models/LocalPackageInstallModel.cs | 10 +- src/Umbraco.Web/Models/PackageInstallModel.cs | 10 +- .../Runtime/WebRuntimeComponent.cs | 5 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 - .../FileUploadCleanupFilterAttribute.cs | 16 +- .../_Legacy/PackageActions/addApplication.cs | 2 +- .../PackageActions/addDashboardSection.cs | 98 ----- .../PackageActions/addProxyFeedHost.cs | 2 +- .../_Legacy/PackageActions/allowDoctype.cs | 3 +- .../PackageActions/publishRootDocument.cs | 4 +- 52 files changed, 669 insertions(+), 795 deletions(-) delete mode 100644 src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index a09462c806..bd07123fb2 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -72,7 +72,6 @@ namespace Umbraco.Core.Composing.Composers new PackageInstallation( factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - SystemDirectories.Packages, appRoot, appRoot)); //TODO: These are replaced in the web project - we need to declare them so that diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 3121e869c3..acb12ab575 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -405,7 +405,7 @@ namespace Umbraco.Core.Composing break; case LocalTempStorage.Default: default: - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/TypesCache"); + var tempFolder = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache"); _fileBasePath = Path.Combine(tempFolder, "umbraco-types." + NetworkHelper.FileSafeMachineName); break; } diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 7773f378a5..76e7631482 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -31,16 +31,6 @@ namespace Umbraco.Core.IO public static char DirSepChar => Path.DirectorySeparatorChar; - internal static void UnZip(string zipFilePath, string unPackDirectory, bool deleteZipFile) - { - // Unzip - var tempDir = unPackDirectory; - Directory.CreateDirectory(tempDir); - ZipFile.ExtractToDirectory(zipFilePath, unPackDirectory); - if (deleteZipFile) - File.Delete(zipFilePath); - } - //helper to try and match the old path to a new virtual one public static string FindFile(string virtualPath) { @@ -123,11 +113,6 @@ namespace Umbraco.Core.IO return MapPath(path, true); } - public static string MapPathIfVirtual(string path) - { - return path.StartsWith("~/") ? MapPath(path) : path; - } - //use a tilde character instead of the complete path internal static string ReturnPath(string settingsKey, string standardPath, bool useTilde) { @@ -156,20 +141,6 @@ namespace Umbraco.Core.IO return VerifyEditPath(filePath, new[] { validDir }); } - /// - /// Validates that the current filepath matches a directory where the user is allowed to edit a file. - /// - /// The filepath to validate. - /// The valid directory. - /// True, if the filepath is valid, else an exception is thrown. - /// The filepath is invalid. - internal static bool ValidateEditPath(string filePath, string validDir) - { - if (VerifyEditPath(filePath, validDir) == false) - throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), ""))); - return true; - } - /// /// Verifies that the current filepath matches one of several directories where the user is allowed to edit a file. /// @@ -221,20 +192,6 @@ namespace Umbraco.Core.IO return ext != null && validFileExtensions.Contains(ext.TrimStart('.')); } - /// - /// Validates that the current filepath has one of several authorized extensions. - /// - /// The filepath to validate. - /// The valid extensions. - /// True, if the filepath is valid, else an exception is thrown. - /// The filepath is invalid. - internal static bool ValidateFileExtension(string filePath, List validFileExtensions) - { - if (VerifyFileExtension(filePath, validFileExtensions) == false) - throw new FileSecurityException(String.Format("The extension for the current file '{0}' is not of an allowed type for this editor. This is typically controlled from either the installed MacroEngines or based on configuration in /config/umbracoSettings.config", filePath.Replace(MapPath(SystemDirectories.Root), ""))); - return true; - } - public static bool PathStartsWith(string path, string root, char separator) { // either it is identical to root, @@ -329,17 +286,6 @@ namespace Umbraco.Core.IO Directory.CreateDirectory(absolutePath); } - public static void EnsureFileExists(string path, string contents) - { - var absolutePath = IOHelper.MapPath(path); - if (File.Exists(absolutePath)) return; - - using (var writer = File.CreateText(absolutePath)) - { - writer.Write(contents); - } - } - /// /// Checks if a given path is a full path including drive letter /// diff --git a/src/Umbraco.Core/IO/ShadowWrapper.cs b/src/Umbraco.Core/IO/ShadowWrapper.cs index 6493238391..d71f328713 100644 --- a/src/Umbraco.Core/IO/ShadowWrapper.cs +++ b/src/Umbraco.Core/IO/ShadowWrapper.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.IO { internal class ShadowWrapper : IFileSystem { - private const string ShadowFsPath = "~/App_Data/TEMP/ShadowFs"; + private static readonly string ShadowFsPath = SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"; private readonly Func _isScoped; private readonly IFileSystem _innerFileSystem; diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index 94aa7b16cc..4ea3ed64d5 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -12,6 +12,10 @@ namespace Umbraco.Core.IO public static string Data => "~/App_Data"; + public static string TempData => Data + "/TEMP"; + + public static string TempFileUploads => TempData + "/FileUploads"; + public static string Install => "~/install"; //fixme: remove this diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index 266c1f5518..d458337bf9 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Xml.Linq; @@ -10,7 +11,7 @@ namespace Umbraco.Core.Models.Packaging /// public class CompiledPackage : IPackageInfo { - public string PackageFileName { get; set; } + public FileInfo PackageFile { get; set; } public string Name { get; set; } public string Version { get; set; } diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index 7d81f48dd2..1cab17e220 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable StylesheetsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); public IEnumerable Actions { get; set; } = Enumerable.Empty(); - public bool PackageInstalled { get; set; } + public IEnumerable ActionErrors { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index de8415ddd2..bab52c63f6 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -53,6 +53,9 @@ namespace Umbraco.Core.Models.Packaging [Url] public string Url { get; set; } = string.Empty; + /// + /// The full path to the package's zip file when it was installed (or is being installed) + /// [ReadOnly(true)] [DataMember(Name = "packagePath")] public string PackagePath { get; set; } = string.Empty; diff --git a/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs index 20cbedbcf0..fd39954f6b 100644 --- a/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs @@ -16,9 +16,9 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable MacrosUninstalled { get; set; } = Enumerable.Empty(); public IEnumerable FilesUninstalled { get; set; } = Enumerable.Empty(); public IEnumerable TemplatesUninstalled { get; set; } = Enumerable.Empty(); - public IEnumerable ContentTypesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable DocumentTypesUninstalled { get; set; } = Enumerable.Empty(); public IEnumerable StylesheetsUninstalled { get; set; } = Enumerable.Empty(); - public IEnumerable ContentUninstalled { get; set; } = Enumerable.Empty(); - public bool PackageUninstalled { get; set; } + public IEnumerable Actions { get; set; } = Enumerable.Empty(); + public IEnumerable ActionErrors { get; set; } = Enumerable.Empty(); } } diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 0f3119f697..eb9cf46008 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Packaging _conflictingPackageData = conflictingPackageData; } - public CompiledPackage ToCompiledPackage(XDocument xml, string packageFileName, string applicationRootFolder) + public CompiledPackage ToCompiledPackage(XDocument xml, FileInfo packageFile, string applicationRootFolder) { if (xml == null) throw new ArgumentNullException(nameof(xml)); if (xml.Root == null) throw new ArgumentException(nameof(xml), "The xml document is invalid"); @@ -39,7 +39,7 @@ namespace Umbraco.Core.Packaging var def = new CompiledPackage { - PackageFileName = packageFileName, + PackageFile = packageFile, Name = package.Element("name")?.Value, Author = author.Element("name")?.Value, AuthorUrl = author.Element("website")?.Value, diff --git a/src/Umbraco.Core/Packaging/IPackageActionRunner.cs b/src/Umbraco.Core/Packaging/IPackageActionRunner.cs index d5c6327115..1f8c134364 100644 --- a/src/Umbraco.Core/Packaging/IPackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/IPackageActionRunner.cs @@ -1,4 +1,5 @@ -using System.Xml.Linq; +using System.Collections.Generic; +using System.Xml.Linq; namespace Umbraco.Core.Packaging { @@ -10,7 +11,8 @@ namespace Umbraco.Core.Packaging /// Name of the package. /// The action alias. /// The action XML. - void RunPackageAction(string packageName, string actionAlias, XElement actionXml); + /// + bool RunPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors); /// /// Undos the package action with the specified action alias. @@ -18,6 +20,7 @@ namespace Umbraco.Core.Packaging /// Name of the package. /// The action alias. /// The action XML. - void UndoPackageAction(string packageName, string actionAlias, XElement actionXml); + /// + bool UndoPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 83a21dcd2f..5dae76674d 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Xml.Linq; using Umbraco.Core.Models.Packaging; @@ -6,6 +7,14 @@ namespace Umbraco.Core.Packaging { public interface IPackageInstallation { + /// + /// Uninstalls a package including all data, entities and files + /// + /// + /// + /// + UninstallationSummary UninstallPackage(PackageDefinition packageDefinition, int userId); + /// /// Installs a packages data and entities /// @@ -27,8 +36,8 @@ namespace Umbraco.Core.Packaging /// /// Reads the package (zip) file and returns the model /// - /// + /// /// - CompiledPackage ReadPackage(string packageFileName); + CompiledPackage ReadPackage(FileInfo packageFile); } } diff --git a/src/Umbraco.Core/Packaging/PackageActionRunner.cs b/src/Umbraco.Core/Packaging/PackageActionRunner.cs index 37103b0473..38275d5f0a 100644 --- a/src/Umbraco.Core/Packaging/PackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/PackageActionRunner.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Xml.Linq; using Umbraco.Core.Logging; using Umbraco.Core._Legacy.PackageActions; @@ -19,15 +20,10 @@ namespace Umbraco.Core.Packaging _packageActions = packageActions; } - /// - /// Runs the package action with the specified action alias. - /// - /// Name of the package. - /// The action alias. - /// The action XML. - public void RunPackageAction(string packageName, string actionAlias, XElement actionXml) + /// + public bool RunPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors) { - + var e = new List(); foreach (var ipa in _packageActions) { try @@ -37,19 +33,19 @@ namespace Umbraco.Core.Packaging } catch (Exception ex) { + e.Add($"{ipa.Alias()} - {ex.Message}"); _logger.Error(ex, "Error loading package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } + + errors = e; + return e.Count == 0; } - /// - /// Undos the package action with the specified action alias. - /// - /// Name of the package. - /// The action alias. - /// The action XML. - public void UndoPackageAction(string packageName, string actionAlias, XElement actionXml) + /// + public bool UndoPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors) { + var e = new List(); foreach (var ipa in _packageActions) { try @@ -59,9 +55,12 @@ namespace Umbraco.Core.Packaging } catch (Exception ex) { + e.Add($"{ipa.Alias()} - {ex.Message}"); _logger.Error(ex, "Error undoing package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } + errors = e; + return e.Count == 0; } } diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 8ef99502c8..1743bb0041 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Web; @@ -10,6 +11,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; @@ -43,6 +45,128 @@ namespace Umbraco.Core.Packaging _contentService = contentService; } + #region Uninstall + + public UninstallationSummary UninstallPackageData(PackageDefinition package, int userId) + { + if (package == null) throw new ArgumentNullException(nameof(package)); + + var removedTemplates = new List(); + var removedMacros = new List(); + var removedContentTypes = new List(); + var removedDictionaryItems = new List(); + var removedDataTypes = new List(); + var removedLanguages = new List(); + + + //Uninstall templates + foreach (var item in package.Templates.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var found = _fileService.GetTemplate(nId); + if (found != null) + { + removedTemplates.Add(found); + _fileService.DeleteTemplate(found.Alias, userId); + } + package.Templates.Remove(nId.ToString()); + } + + //Uninstall macros + foreach (var item in package.Macros.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var macro = _macroService.GetById(nId); + if (macro != null) + { + removedMacros.Add(macro); + _macroService.Delete(macro, userId); + } + package.Macros.Remove(nId.ToString()); + } + + //Remove Document Types + var contentTypes = new List(); + var contentTypeService = _contentTypeService; + foreach (var item in package.DocumentTypes.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var contentType = contentTypeService.Get(nId); + if (contentType == null) continue; + contentTypes.Add(contentType); + package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); + } + + //Order the DocumentTypes before removing them + if (contentTypes.Any()) + { + //TODO: I don't think this ordering is necessary + var orderedTypes = (from contentType in contentTypes + orderby contentType.ParentId descending, contentType.Id descending + select contentType).ToList(); + removedContentTypes.AddRange(orderedTypes); + contentTypeService.Delete(orderedTypes, userId); + } + + //Remove Dictionary items + foreach (var item in package.DictionaryItems.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var di = _localizationService.GetDictionaryItemById(nId); + if (di != null) + { + removedDictionaryItems.Add(di); + _localizationService.Delete(di, userId); + } + package.DictionaryItems.Remove(nId.ToString()); + } + + //Remove Data types + foreach (var item in package.DataTypes.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var dtd = _dataTypeService.GetDataType(nId); + if (dtd != null) + { + removedDataTypes.Add(dtd); + _dataTypeService.Delete(dtd, userId); + } + package.DataTypes.Remove(nId.ToString()); + } + + //Remove Langs + foreach (var item in package.Languages.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var lang = _localizationService.GetLanguageById(nId); + if (lang != null) + { + removedLanguages.Add(lang); + _localizationService.Delete(lang, userId); + } + package.Languages.Remove(nId.ToString()); + } + + // create a summary of what was actually removed, for PackagingService.UninstalledPackage + var summary = new UninstallationSummary + { + MetaData = package, + TemplatesUninstalled = removedTemplates, + MacrosUninstalled = removedMacros, + DocumentTypesUninstalled = removedContentTypes, + DictionaryItemsUninstalled = removedDictionaryItems, + DataTypesUninstalled = removedDataTypes, + LanguagesUninstalled = removedLanguages, + + }; + + return summary; + + + } + + #endregion + #region Content @@ -201,7 +325,7 @@ namespace Umbraco.Core.Packaging #endregion - #region ContentTypes + #region DocumentTypes public IEnumerable ImportDocumentType(XElement docTypeElement, int userId) { @@ -576,6 +700,7 @@ namespace Umbraco.Core.Packaging // This means that the property will not be created. if (dataTypeDefinition == null) { + //TODO: We should expose this to the UI during install! _logger.Warn("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.", property.Element("Name").Value, dataTypeDefinitionId, property.Element("Type").Value.Trim()); diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 1f0e5ec92e..0d7adf8ece 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -91,7 +91,7 @@ namespace Umbraco.Core.Packaging new XElement("datatypes", string.Join(",", def.DataTypes ?? Array.Empty())), new XElement("content", - new XAttribute("nodeId", def.ContentNodeId), + new XAttribute("nodeId", def.ContentNodeId ?? string.Empty), new XAttribute("loadChildNodes", def.ContentLoadChildNodes)), new XElement("templates", string.Join(",", def.Templates ?? Array.Empty())), diff --git a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs index 55b8bdc63e..7c0891175b 100644 --- a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs @@ -53,6 +53,32 @@ namespace Umbraco.Core.Packaging } } + public IEnumerable UninstallFiles(PackageDefinition package) + { + var removedFiles = new List(); + + foreach (var item in package.Files.ToArray()) + { + removedFiles.Add(item.GetRelativePath()); + + //here we need to try to find the file in question as most packages does not support the tilde char + var file = IOHelper.FindFile(item); + if (file != null) + { + //TODO: Surely this should be ~/ ? + file = file.EnsureStartsWith("/"); + var filePath = IOHelper.MapPath(file); + + if (File.Exists(filePath)) + File.Delete(filePath); + + } + package.Files.Remove(file); + } + + return removedFiles; + } + private static IEnumerable<(string packageUniqueFile, string appAbsolutePath)> AppendRootToDestination(string applicationRootFolder, IEnumerable<(string packageUniqueFile, string appRelativePath)> sourceDestination) { return diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 12d4769235..4563d31560 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -18,7 +18,6 @@ namespace Umbraco.Core.Packaging private readonly PackageFileInstallation _packageFileInstallation; private readonly CompiledPackageXmlParser _parser; private readonly IPackageActionRunner _packageActionRunner; - private readonly string _packagesFolderPath; private readonly DirectoryInfo _packageExtractionFolder; private readonly DirectoryInfo _applicationRootFolder; @@ -29,9 +28,6 @@ namespace Umbraco.Core.Packaging /// /// /// - /// - /// The relative path of the package storage folder (i.e. ~/App_Data/Packages ) - /// /// /// The root folder of the application /// @@ -39,27 +35,25 @@ namespace Umbraco.Core.Packaging /// The destination root folder to extract the package files (generally the same as applicationRoot) but can be modified for testing /// public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, - string packagesFolderPath, DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) + DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) { _packageExtraction = new PackageExtraction(); _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); _packageDataInstallation = packageDataInstallation ?? throw new ArgumentNullException(nameof(packageDataInstallation)); - _parser = parser; - _packageActionRunner = packageActionRunner; - _packagesFolderPath = packagesFolderPath; - _applicationRootFolder = applicationRootFolder; - _packageExtractionFolder = packageExtractionFolder; + _parser = parser ?? throw new ArgumentNullException(nameof(parser)); + _packageActionRunner = packageActionRunner ?? throw new ArgumentNullException(nameof(packageActionRunner)); + _applicationRootFolder = applicationRootFolder ?? throw new ArgumentNullException(nameof(applicationRootFolder)); + _packageExtractionFolder = packageExtractionFolder ?? throw new ArgumentNullException(nameof(packageExtractionFolder)); } - public CompiledPackage ReadPackage(string packageFileName) + public CompiledPackage ReadPackage(FileInfo packageFile) { - if (packageFileName == null) throw new ArgumentNullException(nameof(packageFileName)); - var packageZipFile = GetPackageZipFile(packageFileName); - var doc = GetConfigXmlDoc(packageZipFile); + if (packageFile == null) throw new ArgumentNullException(nameof(packageFile)); + var doc = GetConfigXmlDoc(packageFile); - var compiledPackage = _parser.ToCompiledPackage(doc, Path.GetFileName(packageZipFile.FullName), _applicationRootFolder.FullName); + var compiledPackage = _parser.ToCompiledPackage(doc, packageFile, _applicationRootFolder.FullName); - ValidatePackageFile(packageZipFile, compiledPackage); + ValidatePackageFile(packageFile, compiledPackage); return compiledPackage; } @@ -73,15 +67,28 @@ namespace Umbraco.Core.Packaging if (packageDefinition.Name != compiledPackage.Name) throw new InvalidOperationException("The package definition does not match the compiled package manifest"); - var packageZipFile = GetPackageZipFile(compiledPackage.PackageFileName); + var packageZipFile = compiledPackage.PackageFile; return _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _packageExtractionFolder.FullName); } + public UninstallationSummary UninstallPackage(PackageDefinition package, int userId) + { + //running this will update the PackageDefinition with the items being removed + var summary = _packageDataInstallation.UninstallPackageData(package, userId); + summary.Actions = _parser.GetPackageActions(XElement.Parse(package.Actions), package.Name); + + //run actions before files are removed + summary.ActionErrors = UndoPackageActions(package, summary.Actions).ToList(); + + var filesRemoved = _packageFileInstallation.UninstallFiles(package); + summary.FilesUninstalled = filesRemoved; + + return summary; + } + public InstallationSummary InstallPackageData(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId) { - //TODO: Update the PackageDefinition! - var installationSummary = new InstallationSummary { DataTypesInstalled = _packageDataInstallation.ImportDataTypes(compiledPackage.DataTypes.ToList(), userId), @@ -101,10 +108,8 @@ namespace Umbraco.Core.Packaging installationSummary.MetaData = compiledPackage; //fixme: Verify that this will work! installationSummary.FilesInstalled = packageDefinition.Files; - installationSummary.PackageInstalled = true; - + //make sure the definition is up to date with everything - foreach (var x in installationSummary.DataTypesInstalled) packageDefinition.DataTypes.Add(x.Id.ToInvariantString()); foreach (var x in installationSummary.LanguagesInstalled) packageDefinition.Languages.Add(x.Id.ToInvariantString()); foreach (var x in installationSummary.DictionaryItemsInstalled) packageDefinition.DictionaryItems.Add(x.Id.ToInvariantString()); @@ -115,15 +120,17 @@ namespace Umbraco.Core.Packaging var contentInstalled = installationSummary.ContentInstalled.ToList(); packageDefinition.ContentNodeId = contentInstalled.Count > 0 ? contentInstalled[0].Id.ToInvariantString() : null; - RunPackageActions(packageDefinition, installationSummary.Actions); + //run package actions + installationSummary.ActionErrors = RunPackageActions(packageDefinition, installationSummary.Actions).ToList(); return installationSummary; } - private void RunPackageActions(PackageDefinition packageDefinition, IEnumerable actions) + private IEnumerable RunPackageActions(PackageDefinition packageDefinition, IEnumerable actions) { foreach (var n in actions) { + //if there is an undo section then save it to the definition so we can run it at uninstallation var undo = n.Undo; if (undo) packageDefinition.Actions += n.XmlData.ToString(); @@ -131,12 +138,28 @@ namespace Umbraco.Core.Packaging //Run the actions tagged only for 'install' if (n.RunAt != ActionRunAt.Install) continue; - if (n.Alias.IsNullOrWhiteSpace() == false) - _packageActionRunner.RunPackageAction(packageDefinition.Name, n.Alias, n.XmlData); + if (n.Alias.IsNullOrWhiteSpace()) continue; + + //run the actions and report errors + if (!_packageActionRunner.RunPackageAction(packageDefinition.Name, n.Alias, n.XmlData, out var err)) + foreach (var e in err) yield return e; } } - private FileInfo GetPackageZipFile(string packageFileName) => new FileInfo(IOHelper.MapPath(_packagesFolderPath).EnsureEndsWith('\\') + packageFileName); + private IEnumerable UndoPackageActions(IPackageInfo packageDefinition, IEnumerable actions) + { + foreach (var n in actions) + { + //Run the actions tagged only for 'uninstall' + if (n.RunAt != ActionRunAt.Uninstall) continue; + + if (n.Alias.IsNullOrWhiteSpace()) continue; + + //run the actions and report errors + if (!_packageActionRunner.UndoPackageAction(packageDefinition.Name, n.Alias, n.XmlData, out var err)) + foreach (var e in err) yield return e; + } + } private XDocument GetConfigXmlDoc(FileInfo packageFile) { diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index c0620820a2..af5c7ffded 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -69,7 +69,7 @@ namespace Umbraco.Core.Packaging _logger = logger; _packageRepositoryFileName = packageRepositoryFileName; - _tempFolderPath = tempFolderPath ?? SystemDirectories.Data + "/TEMP/PackageFiles"; + _tempFolderPath = tempFolderPath ?? SystemDirectories.TempData.EnsureEndsWith('/') + "PackageFiles"; _packagesFolderPath = packagesFolderPath ?? SystemDirectories.Packages; _mediaFolderPath = mediaFolderPath ?? SystemDirectories.Media + "/created-packages"; diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 8aa936c8ff..a31fc2d6cf 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -16,25 +16,27 @@ namespace Umbraco.Core.Services /// /// Returns a result from an umbraco package file (zip) /// - /// + /// /// - CompiledPackage GetCompiledPackageInfo(string packageFileName); + CompiledPackage GetCompiledPackageInfo(FileInfo packageFile); /// /// Installs the package files contained in an umbraco package file (zip) /// /// - /// + /// /// - IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0); + IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); /// /// Installs the data, entities, objects contained in an umbraco package file (zip) /// /// - /// + /// /// - InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0); + InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); + + UninstallationSummary UninstallPackage(PackageDefinition packageDefinition, int userId = 0); #endregion @@ -81,6 +83,6 @@ namespace Umbraco.Core.Services /// /// The file name of the downloaded package which will exist in ~/App_Data/packages /// - Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId); + Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId); } } diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index ba5d30f8d7..362b1fc67b 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -53,7 +53,7 @@ namespace Umbraco.Core.Services.Implement #region Package Files /// - public async Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId) + public async Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId) { //includeHidden = true because we don't care if it's hidden we want to get the file regardless var url = $"{Constants.PackageRepository.RestApiBaseUrl}/{packageId}?version={umbracoVersion.ToString(3)}&includeHidden=true&asFile=true"; @@ -85,7 +85,7 @@ namespace Umbraco.Core.Services.Implement using (var fs1 = new FileStream(packageFilePath, FileMode.Create)) { fs1.Write(bytes, 0, bytes.Length); - return packageId + ".umb"; + return new FileInfo(packageFilePath); } } @@ -97,18 +97,19 @@ namespace Umbraco.Core.Services.Implement #region Installation - public CompiledPackage GetCompiledPackageInfo(string packageFileName) => _packageInstallation.ReadPackage(packageFileName); + public CompiledPackage GetCompiledPackageInfo(FileInfo packageFile) => _packageInstallation.ReadPackage(packageFile); - public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0) + public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); if (packageDefinition.Name == default) throw new ArgumentException("The package definition has incomplete information"); - var compiledPackage = GetCompiledPackageInfo(packageFileName); - if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName); + var compiledPackage = GetCompiledPackageInfo(packageFile); + if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFile); - var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId); + var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId).ToList(); + packageDefinition.Files = files; SaveInstalledPackage(packageDefinition); @@ -117,16 +118,16 @@ namespace Umbraco.Core.Services.Implement return files; } - public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0) + public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); if (packageDefinition.Name == default) throw new ArgumentException("The package definition has incomplete information"); - var compiledPackage = GetCompiledPackageInfo(packageFileName); - if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName); + var compiledPackage = GetCompiledPackageInfo(packageFile); + if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFile); - if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFileName, compiledPackage), this)) + if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFile.Name, compiledPackage), this)) return new InstallationSummary { MetaData = compiledPackage }; var summary = _packageInstallation.InstallPackageData(packageDefinition, compiledPackage, userId); @@ -140,6 +141,20 @@ namespace Umbraco.Core.Services.Implement return summary; } + public UninstallationSummary UninstallPackage(PackageDefinition package, int userId = 0) + { + var summary = _packageInstallation.UninstallPackage(package, userId); + + SaveInstalledPackage(package); + + DeleteInstalledPackage(package.Id, userId); + + // trigger the UninstalledPackage event + UninstalledPackage.RaiseEvent(new UninstallPackageEventArgs(summary, package, false), this); + + return summary; + } + #endregion #region Created/Installed Package Repositories @@ -179,21 +194,12 @@ namespace Umbraco.Core.Services.Implement #endregion - /// - /// This method can be used to trigger the 'UninstalledPackage' event when a package is uninstalled by something else but this service. - /// - /// - internal static void OnUninstalledPackage(UninstallPackageEventArgs args) - { - UninstalledPackage.RaiseEvent(args, null); - } - #region Event Handlers /// /// Occurs before Importing umbraco package /// - internal static event TypedEventHandler> ImportingPackage; + public static event TypedEventHandler> ImportingPackage; /// /// Occurs after a package is imported diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs index 5cfcb501e5..6844e6e75c 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs @@ -551,7 +551,7 @@ namespace Umbraco.Core.Sync break; case LocalTempStorage.Default: default: - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/DistCache"); + var tempFolder = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "DistCache"); distCacheFilePath = Path.Combine(tempFolder, fileName); break; } diff --git a/src/Umbraco.Examine/LuceneIndexCreator.cs b/src/Umbraco.Examine/LuceneIndexCreator.cs index 0e83b37dc5..806d0edc7a 100644 --- a/src/Umbraco.Examine/LuceneIndexCreator.cs +++ b/src/Umbraco.Examine/LuceneIndexCreator.cs @@ -29,7 +29,7 @@ namespace Umbraco.Examine public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string folderName) { - var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Data), "TEMP", "ExamineIndexes", folderName)); + var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.TempData), "ExamineIndexes", folderName)); if (!dirInfo.Exists) System.IO.Directory.CreateDirectory(dirInfo.FullName); diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 5148c7eb1b..1649f3675d 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -30,7 +30,7 @@ namespace Umbraco.Tests.Composing // this ensures it's reset _typeLoader = new TypeLoader(NullCacheProvider.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of())); - foreach (var file in Directory.GetFiles(IOHelper.MapPath("~/App_Data/TEMP/TypesCache"))) + foreach (var file in Directory.GetFiles(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache"))) File.Delete(file); // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver diff --git a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs index 262b026cae..2244f9085d 100644 --- a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.IO private static void ClearFiles() { TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests")); - TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data/TEMP/ShadowFs")); + TestHelper.DeleteDirectory(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); } private static string NormPath(string path) @@ -388,7 +388,7 @@ namespace Umbraco.Tests.IO var logger = Mock.Of(); var path = IOHelper.MapPath("FileSysTests"); - var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs"); + var shadowfs = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); Directory.CreateDirectory(shadowfs); @@ -482,7 +482,7 @@ namespace Umbraco.Tests.IO var logger = Mock.Of(); var path = IOHelper.MapPath("FileSysTests"); - var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs"); + var shadowfs = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; @@ -535,7 +535,7 @@ namespace Umbraco.Tests.IO var logger = Mock.Of(); var path = IOHelper.MapPath("FileSysTests"); - var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs"); + var shadowfs = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 609d26aec9..7514eea00b 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -50,11 +50,10 @@ namespace Umbraco.Tests.Packaging PackageDataInstallation, new PackageFileInstallation(Parser, ProfilingLogger), Parser, Mock.Of(), - packagesFolderPath: "~/Packaging/packages",//this is where our test zip file is applicationRootFolder: new DirectoryInfo(IOHelper.GetRootDirectorySafe()), packageExtractionFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder - const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; + private const string DocumentTypePickerUmb = "Document_Type_Picker_1.1.umb"; //[Test] //public void PackagingService_Can_ImportPackage() @@ -72,7 +71,9 @@ namespace Umbraco.Tests.Packaging [Test] public void Can_Read_Compiled_Package() { - var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); Assert.IsNotNull(package); Assert.AreEqual(1, package.Files.Count); Assert.AreEqual("095e064b-ba4d-442d-9006-3050983c13d8.dll", package.Files[0].UniqueFileName); @@ -95,7 +96,10 @@ namespace Umbraco.Tests.Packaging { - var preInstallWarnings = PackageInstallation.ReadPackage(documentTypePickerUmb).Warnings; + var preInstallWarnings = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))) + .Warnings; Assert.IsNotNull(preInstallWarnings); //TODO: Assert! @@ -104,7 +108,9 @@ namespace Umbraco.Tests.Packaging [Test] public void Install_Files() { - var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); @@ -122,7 +128,9 @@ namespace Umbraco.Tests.Packaging [Test] public void Install_Data() { - var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); diff --git a/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs b/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs index 0ef0e9362b..0a23e4a1b9 100644 --- a/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Scoping { TestHelper.DeleteDirectory(IOHelper.MapPath("media")); TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests")); - TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data/TEMP/ShadowFs")); + TestHelper.DeleteDirectory(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); } [TestCase(true)] diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 412a492376..684da2599e 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -185,7 +185,8 @@ namespace Umbraco.Tests.TestHelpers new PackageDataInstallation(logger, fileService.Value, macroService.Value, localizationService.Value, dataTypeService.Value, entityService.Value, contentTypeService.Value, contentService.Value, propertyEditorCollection), new PackageFileInstallation(compiledPackageXmlParser, new ProfilingLogger(logger, new TestProfiler())), compiledPackageXmlParser, Mock.Of(), - "", null, null)); + new DirectoryInfo(IOHelper.GetRootDirectorySafe()), + new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 057f1160c2..4afe62786e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -144,6 +144,8 @@ vm.package = updatedPackage; vm.buttonState = "success"; + formHelper.resetForm({ scope: $scope }); + if (create) { //if we are creating, then redirect to the correct url and reload $location.path("packages/packages/edit/" + vm.package.id).search("subview", "created").search("create", null); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 955676b806..a66eb94746 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -138,7 +138,7 @@ {{doctype.name}} diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js index 8be7d1b17a..9c6c2bb7c5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js @@ -10,7 +10,7 @@ vm.installPackage = installPackage; vm.installState = { status: "", - progress:0 + progress: 0 }; vm.installCompleted = false; vm.zipFile = { @@ -27,6 +27,23 @@ } }; + var labels = {}; + var labelKeys = [ + "packager_installStateImporting", + "packager_installStateInstalling", + "packager_installStateRestarting", + "packager_installStateComplete", + "packager_installStateCompleted" + ]; + + localizationService.localizeMany(labelKeys).then(function (values) { + labels.installStateImporting = values[0]; + labels.installStateInstalling = values[1]; + labels.installStateRestarting = values[2]; + labels.installStateComplete = values[3]; + labels.installStateCompleted = values[4]; + }); + function upload(file) { Upload.upload({ @@ -34,10 +51,10 @@ fields: {}, file: file }).progress(function (evt) { - + // hack: in some browsers the progress event is called after success // this prevents the UI from going back to a uploading state - if(vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") { + if (vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") { // set view state to uploading vm.state = 'uploading'; @@ -110,83 +127,85 @@ } function installPackage() { - vm.installState.status = localizationService.localize("packager_installStateImporting"); + + vm.installState.status = labels.installStateImporting; vm.installState.progress = "0"; packageResource - .import(vm.localPackage) - .then(function(pack) { - vm.installState.progress = "25"; - vm.installState.status = localizationService.localize("packager_installStateInstalling"); - return packageResource.installFiles(pack); - }, + .import(vm.localPackage) + .then(function (pack) { + vm.installState.progress = "25"; + vm.installState.status = labels.installStateInstalling; + return packageResource.installFiles(pack); + }, installError) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateRestarting"); - vm.installState.progress = "50"; - var deferred = $q.defer(); + .then(function (pack) { + vm.installState.status = labels.installStateRestarting; + vm.installState.progress = "50"; + var deferred = $q.defer(); - //check if the app domain is restarted ever 2 seconds - var count = 0; - function checkRestart() { - $timeout(function () { + //check if the app domain is restarted ever 2 seconds + var count = 0; + + function checkRestart() { + $timeout(function () { packageResource.checkRestart(pack).then(function (d) { count++; //if there is an id it means it's not restarted yet but we'll limit it to only check 10 times if (d.isRestarting && count < 10) { - checkRestart(); + checkRestart(); } else { - //it's restarted! - deferred.resolve(d); + //it's restarted! + deferred.resolve(d); } - }, - installError); - }, 2000); - } + }, + installError); + }, + 2000); + } - checkRestart(); - - return deferred.promise; - }, installError) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateRestarting"); - vm.installState.progress = "75"; - return packageResource.installData(pack); - }, + checkRestart(); + + return deferred.promise; + }, installError) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateComplete"); - vm.installState.progress = "100"; - return packageResource.cleanUp(pack); - }, + .then(function (pack) { + vm.installState.status = labels.installStateRestarting; + vm.installState.progress = "75"; + return packageResource.installData(pack); + }, installError) - .then(function(result) { + .then(function (pack) { + vm.installState.status = labels.installStateComplete; + vm.installState.progress = "100"; + return packageResource.cleanUp(pack); + }, + installError) + .then(function (result) { - if (result.postInstallationPath) { - //Put the redirect Uri in a cookie so we can use after reloading - localStorageService.set("packageInstallUri", result.postInstallationPath); - } - else { - //set to a constant value so it knows to just go to the installed view - localStorageService.set("packageInstallUri", "installed"); - } + if (result.postInstallationPath) { + //Put the redirect Uri in a cookie so we can use after reloading + localStorageService.set("packageInstallUri", result.postInstallationPath); + } + else { + //set to a constant value so it knows to just go to the installed view + localStorageService.set("packageInstallUri", "installed"); + } - vm.installState.status = localizationService.localize("packager_installStateCompleted"); - vm.installCompleted = true; - - + vm.installState.status = labels.installStateCompleted; + vm.installCompleted = true; - }, - installError); + + }, installError); } - + function installError() { //This will return a rejection meaning that the promise change above will stop return $q.reject(); } - vm.reloadPage = function() { + vm.reloadPage = function () { //reload on next digest (after cookie) $timeout(function () { $window.location.reload(true); diff --git a/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs b/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs index 8c3edd915d..dd6d22a967 100644 --- a/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs +++ b/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Web.Http; using System.Web.Http.Controllers; using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Web.Models.ContentEditing; @@ -19,7 +20,7 @@ namespace Umbraco.Web.Editors.Binders public TModelSave BindModelFromMultipartRequest(HttpActionContext actionContext, ModelBindingContext bindingContext) where TModelSave : IHaveUploadedFiles { - var result = actionContext.ReadAsMultipart("~/App_Data/TEMP/FileUploads"); + var result = actionContext.ReadAsMultipart(SystemDirectories.TempFileUploads); var model = actionContext.GetModelFromMultipartRequest(result, "contentItem"); diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 97f7ff3589..670d37e7a7 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; @@ -532,7 +533,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "FileUploads"); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); @@ -545,26 +546,24 @@ namespace Umbraco.Web.Editors } var model = new ContentTypeImportModel(); + var file = result.FileData[0]; var fileName = file.Headers.ContentDisposition.FileName.Trim('\"'); var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower(); if (ext.InvariantEquals("udt")) { - //TODO: Currently it has to be here, it's not ideal but that's the way it is right now - var tempDir = IOHelper.MapPath(SystemDirectories.Data); + model.TempFileName = Path.Combine(root, model.TempFileName); - //ensure it's there - Directory.CreateDirectory(tempDir); - - model.TempFileName = "justDelete_" + Guid.NewGuid() + ".udt"; - var tempFileLocation = Path.Combine(tempDir, model.TempFileName); - System.IO.File.Copy(file.LocalFileName, tempFileLocation, true); + model.UploadedFiles.Add(new ContentPropertyFile + { + TempFilePath = model.TempFileName + }); var xd = new XmlDocument { XmlResolver = null }; - xd.Load(tempFileLocation); + xd.Load(model.TempFileName); model.Alias = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Alias")?.FirstChild.Value; model.Name = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Name")?.FirstChild.Value; diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 2c6ba06dc2..ce088e0caa 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -626,7 +626,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 4b452ac6a6..063dcf483e 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -13,7 +13,7 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { /// - /// A controller used for installing packages and managing all of the data in the packages section in the back office + /// A controller used for managing packages in the back office /// [PluginController("UmbracoApi")] [SerializeVersion] diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index bfaec3f82c..38b75a27f8 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; @@ -42,14 +43,11 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageInstallController : UmbracoAuthorizedJsonController { - private readonly IPackageActionRunner _packageActionRunner; - public PackageInstallController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, - IProfilingLogger logger, IRuntimeState runtimeState, IPackageActionRunner packageActionRunner) + IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { - _packageActionRunner = packageActionRunner; } /// @@ -75,7 +73,7 @@ namespace Umbraco.Web.Editors var package = Services.PackagingService.GetInstalledPackageById(packageId); if (package == null) return NotFound(); - PerformUninstall(package); + var summary = Services.PackagingService.UninstallPackage(package); //now get all other packages by this name since we'll uninstall all versions foreach (var installed in Services.PackagingService.GetAllInstalledPackages() @@ -94,176 +92,6 @@ namespace Umbraco.Web.Editors return Ok(); } - /// - /// SORRY :( I didn't have time to put this in a service somewhere - the old packager did this all manually too - /// - /// - protected void PerformUninstall(PackageDefinition package) - { - if (package == null) throw new ArgumentNullException("package"); - - var removedTemplates = new List(); - var removedMacros = new List(); - var removedContentTypes = new List(); - var removedDictionaryItems = new List(); - var removedDataTypes = new List(); - var removedFiles = new List(); - - //Uninstall templates - foreach (var item in package.Templates.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var found = Services.FileService.GetTemplate(nId); - if (found != null) - { - removedTemplates.Add(found); - Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId().ResultOr(0)); - } - package.Templates.Remove(nId.ToString()); - } - - //Uninstall macros - foreach (var item in package.Macros.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var macro = Services.MacroService.GetById(nId); - if (macro != null) - { - removedMacros.Add(macro); - Services.MacroService.Delete(macro); - } - package.Macros.Remove(nId.ToString()); - } - - //Remove Document Types - var contentTypes = new List(); - var contentTypeService = Services.ContentTypeService; - foreach (var item in package.DocumentTypes.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var contentType = contentTypeService.Get(nId); - if (contentType == null) continue; - contentTypes.Add(contentType); - package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); - } - - //Order the DocumentTypes before removing them - if (contentTypes.Any()) - { - //TODO: I don't think this ordering is necessary - var orderedTypes = from contentType in contentTypes - orderby contentType.ParentId descending, contentType.Id descending - select contentType; - removedContentTypes.AddRange(orderedTypes); - contentTypeService.Delete(orderedTypes); - } - - //Remove Dictionary items - foreach (var item in package.DictionaryItems.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var di = Services.LocalizationService.GetDictionaryItemById(nId); - if (di != null) - { - removedDictionaryItems.Add(di); - Services.LocalizationService.Delete(di); - } - package.DictionaryItems.Remove(nId.ToString()); - } - - //Remove Data types - foreach (var item in package.DataTypes.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var dtd = Services.DataTypeService.GetDataType(nId); - if (dtd != null) - { - removedDataTypes.Add(dtd); - Services.DataTypeService.Delete(dtd); - } - package.DataTypes.Remove(nId.ToString()); - } - - Services.PackagingService.SaveInstalledPackage(package); - - // uninstall actions - //TODO: We should probably report errors to the UI!! - // This never happened before though, but we should do something now - if (package.Actions.IsNullOrWhiteSpace() == false) - { - try - { - var actionsXml = XDocument.Parse("" + package.Actions + ""); - - Logger.Debug("Executing undo actions: {UndoActionsXml}", actionsXml.ToString(SaveOptions.DisableFormatting)); - - foreach (var n in actionsXml.Root.Elements("Action")) - { - try - { - _packageActionRunner.UndoPackageAction(package.Name, n.AttributeValue("alias"), n); - } - catch (Exception ex) - { - Logger.Error(ex, "An error occurred running undo actions"); - } - } - } - catch (Exception ex) - { - Logger.Error(ex, "An error occurred running undo actions"); - } - } - - //moved remove of files here so custom package actions can still undo - //Remove files - foreach (var item in package.Files.ToArray()) - { - removedFiles.Add(item.GetRelativePath()); - - //here we need to try to find the file in question as most packages does not support the tilde char - var file = IOHelper.FindFile(item); - if (file != null) - { - if (file.StartsWith("/") == false) - file = string.Format("/{0}", file); - var filePath = IOHelper.MapPath(file); - - if (File.Exists(filePath)) - File.Delete(filePath); - - } - package.Files.Remove(file); - } - - Services.PackagingService.SaveInstalledPackage(package); - - Services.PackagingService.DeleteInstalledPackage(package.Id, Security.GetUserId().ResultOr(0)); - - // create a summary of what was actually removed, for PackagingService.UninstalledPackage - var summary = new UninstallationSummary - { - MetaData = package, - TemplatesUninstalled = removedTemplates, - MacrosUninstalled = removedMacros, - ContentTypesUninstalled = removedContentTypes, - DictionaryItemsUninstalled = removedDictionaryItems, - DataTypesUninstalled = removedDataTypes, - FilesUninstalled = removedFiles, - PackageUninstalled = true - }; - - // trigger the UninstalledPackage event - // fixme: This all needs to be part of the service! - PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs(summary, package, false)); - - } - /// /// Returns all installed packages - only shows their latest versions /// @@ -302,7 +130,9 @@ namespace Umbraco.Web.Editors private void PopulateFromPackageData(LocalPackageInstallModel model) { - var ins = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); + var zipFile = new FileInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), model.ZipFileName)); + + var ins = Services.PackagingService.GetCompiledPackageInfo(zipFile); model.Name = ins.Name; model.Author = ins.Author; @@ -365,11 +195,9 @@ namespace Umbraco.Web.Editors public async Task UploadLocalPackage() { if (Request.Content.IsMimeMultipartContent() == false) - { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); - } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); @@ -378,38 +206,36 @@ namespace Umbraco.Web.Editors //must have a file if (result.FileData.Count == 0) - { throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); - } - //TODO: App/Tree Permissions? var model = new LocalPackageInstallModel { + //Generate a new package Id for this, we'll use this later for tracking, when persisting, saving the file, etc... PackageGuid = Guid.NewGuid() }; //get the files foreach (var file in result.FileData) { - var fileName = file.Headers.ContentDisposition.FileName.Trim(new[] { '\"' }); + var fileName = file.Headers.ContentDisposition.FileName.Trim('\"'); var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower(); - //TODO: Only allow .zip if (ext.InvariantEquals("zip") || ext.InvariantEquals("umb")) { - //TODO: Currently it has to be here, it's not ideal but that's the way it is right now - var packageTempDir = IOHelper.MapPath(SystemDirectories.Data); + //we always save package files to /App_Data/packages/package-guid.umb for processing as a standard so lets copy. + + var packagesFolder = IOHelper.MapPath(SystemDirectories.Packages); + Directory.CreateDirectory(packagesFolder); + var packageFile = Path.Combine(packagesFolder, model.PackageGuid + ".umb"); + File.Copy(file.LocalFileName, packageFile); - //ensure it's there - Directory.CreateDirectory(packageTempDir); + model.ZipFileName = Path.GetFileName(packageFile); - //copy it - must always be '.umb' for the installer thing to work - //the file name must be a GUID - this is what the packager expects (strange yes) - //because essentially this is creating a temporary package Id that will be used - //for unpacking/installing/etc... - model.ZipFilePath = model.PackageGuid + ".umb"; - var packageTempFileLocation = Path.Combine(packageTempDir, model.ZipFilePath); - File.Copy(file.LocalFileName, packageTempFileLocation, true); + //add to the outgoing model so that all temp files are cleaned up + model.UploadedFiles.Add(new ContentPropertyFile + { + TempFilePath = file.LocalFileName + }); //Populate the model from the metadata in the package file (zip file) PopulateFromPackageData(model); @@ -447,17 +273,22 @@ namespace Umbraco.Web.Editors public async Task Fetch(string packageGuid) { //Default path - string path = Path.Combine("packages", packageGuid + ".umb"); - if (File.Exists(IOHelper.MapPath(Path.Combine(SystemDirectories.Data, path))) == false) + string fileName = packageGuid + ".umb"; + if (File.Exists(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), fileName)) == false) { - path = await Services.PackagingService.FetchPackageFileAsync(Guid.Parse(packageGuid), UmbracoVersion.Current, Security.GetUserId().ResultOr(0)); + var packageFile = await Services.PackagingService.FetchPackageFileAsync( + Guid.Parse(packageGuid), + UmbracoVersion.Current, + Security.GetUserId().ResultOr(0)); + + fileName = packageFile.Name; } var model = new LocalPackageInstallModel { PackageGuid = Guid.Parse(packageGuid), - RepositoryGuid = Guid.Parse("65194810-1f85-11dd-bd0b-0800200c9a66"), - ZipFilePath = path + //RepositoryGuid = Guid.Parse("65194810-1f85-11dd-bd0b-0800200c9a66"), + ZipFileName = fileName }; //Populate the model from the metadata in the package file (zip file) @@ -483,7 +314,9 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel Import(PackageInstallModel model) { - var packageInfo = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); + var zipFile = new FileInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), model.ZipFileName)); + + var packageInfo = Services.PackagingService.GetCompiledPackageInfo(zipFile); //now we need to check for version comparison if (packageInfo.UmbracoVersionRequirementsType == RequirementsType.Strict) @@ -497,9 +330,10 @@ namespace Umbraco.Web.Editors } var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); + packageDefinition.PackageId = model.PackageGuid; //We must re-map the original package GUID that was generated + packageDefinition.PackagePath = zipFile.FullName; //save to the installedPackages.config - packageDefinition.PackageId = model.PackageGuid; //fixme: why are we doing this? Services.PackagingService.SaveInstalledPackage(packageDefinition); model.Id = packageDefinition.Id; @@ -518,7 +352,9 @@ namespace Umbraco.Web.Editors var definition = Services.PackagingService.GetInstalledPackageById(model.Id); if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); - Services.PackagingService.InstallCompiledPackageFiles(definition, model.ZipFilePath, Security.GetUserId().ResultOr(0)); + var zipFile = new FileInfo(definition.PackagePath); + + var installedFiles = Services.PackagingService.InstallCompiledPackageFiles(definition, zipFile, Security.GetUserId().ResultOr(0)); //set a restarting marker and reset the app pool Current.RestartAppPool(Request.TryGetHttpContext().Result); @@ -553,7 +389,10 @@ namespace Umbraco.Web.Editors var definition = Services.PackagingService.GetInstalledPackageById(model.Id); if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); - Services.PackagingService.InstallCompiledPackageData(definition, model.ZipFilePath, Security.GetUserId().ResultOr(0)); + var zipFile = new FileInfo(definition.PackagePath); + + var installSummary = Services.PackagingService.InstallCompiledPackageData(definition, zipFile, Security.GetUserId().ResultOr(0)); + return model; } @@ -565,7 +404,12 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallResult CleanUp(PackageInstallModel model) { - var packageInfo = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); + var definition = Services.PackagingService.GetInstalledPackageById(model.Id); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); + + var zipFile = new FileInfo(definition.PackagePath); + + var packageInfo = Services.PackagingService.GetCompiledPackageInfo(zipFile); var clientDependencyConfig = new ClientDependencyConfiguration(Logger); var clientDependencyUpdated = clientDependencyConfig.UpdateVersionNumber( @@ -585,9 +429,9 @@ namespace Umbraco.Web.Editors return new PackageInstallResult { Id = model.Id, - ZipFilePath = model.ZipFilePath, + ZipFileName = model.ZipFileName, PackageGuid = model.PackageGuid, - RepositoryGuid = model.RepositoryGuid, + //RepositoryGuid = model.RepositoryGuid, PostInstallationPath = redirectUrl }; diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 7577624621..e46e83c6e4 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -70,7 +70,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs index dd9b0a42d0..81cb1e2e39 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs @@ -1,196 +1,196 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http; -using Newtonsoft.Json.Linq; -using umbraco; -using Umbraco.Core; -using Umbraco.Web.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Services; -using Umbraco.Web.Composing; -using Umbraco.Web.Install.Models; -using Umbraco.Web.WebApi; +//using System; +//using System.Linq; +//using System.Net; +//using System.Net.Http; +//using System.Text; +//using System.Threading.Tasks; +//using System.Web; +//using System.Web.Http; +//using Newtonsoft.Json.Linq; +//using umbraco; +//using Umbraco.Core; +//using Umbraco.Web.Cache; +//using Umbraco.Core.Configuration; +//using Umbraco.Core.Models.Packaging; +//using Umbraco.Core.Services; +//using Umbraco.Web.Composing; +//using Umbraco.Web.Install.Models; +//using Umbraco.Web.WebApi; -namespace Umbraco.Web.Install.Controllers -{ - /// - /// A controller for the installation process regarding packages - /// - /// - /// Currently this is used for web services however we should/could eventually migrate the whole installer to MVC as it - /// is a bit of a mess currently. - /// - [HttpInstallAuthorize] - [AngularJsonOnlyConfiguration] - [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] - //fixme: Is this used anymore?? - public class InstallPackageController : ApiController - { - private readonly IPackagingService _packagingService; - private readonly UmbracoContext _umbracoContext; +//namespace Umbraco.Web.Install.Controllers +//{ +// /// +// /// A controller for the installation process regarding packages +// /// +// /// +// /// Currently this is used for web services however we should/could eventually migrate the whole installer to MVC as it +// /// is a bit of a mess currently. +// /// +// [HttpInstallAuthorize] +// [AngularJsonOnlyConfiguration] +// [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] +// //fixme: Is this used anymore?? +// public class InstallPackageController : ApiController +// { +// private readonly IPackagingService _packagingService; +// private readonly UmbracoContext _umbracoContext; - public InstallPackageController(IPackagingService packagingService, UmbracoContext umbracoContext) - { - _packagingService = packagingService; - _umbracoContext = umbracoContext; - } +// public InstallPackageController(IPackagingService packagingService, UmbracoContext umbracoContext) +// { +// _packagingService = packagingService; +// _umbracoContext = umbracoContext; +// } - /// - /// Empty action, useful for retrieving the base url for this controller - /// - /// - [HttpGet] - public HttpResponseMessage Index() - { - throw new NotImplementedException(); - } +// /// +// /// Empty action, useful for retrieving the base url for this controller +// /// +// /// +// [HttpGet] +// public HttpResponseMessage Index() +// { +// throw new NotImplementedException(); +// } - /// - /// Connects to the repo, downloads the package and creates the definition - /// - /// - /// - [HttpPost] - public async Task DownloadPackageFiles(InstallPackageModel model) - { - var packageFile = await _packagingService.FetchPackageFileAsync( - model.KitGuid, - UmbracoVersion.Current, - UmbracoContext.Current.Security.CurrentUser.Id); +// /// +// /// Connects to the repo, downloads the package and creates the definition +// /// +// /// +// /// +// [HttpPost] +// public async Task DownloadPackageFiles(InstallPackageModel model) +// { +// var packageFile = await _packagingService.FetchPackageFileAsync( +// model.KitGuid, +// UmbracoVersion.Current, +// UmbracoContext.Current.Security.CurrentUser.Id); - var packageInfo = _packagingService.GetCompiledPackageInfo(packageFile); - if (packageInfo == null) throw new InvalidOperationException("Could not read package file " + packageFile); +// var packageInfo = _packagingService.GetCompiledPackageInfo(packageFile); +// if (packageInfo == null) throw new InvalidOperationException("Could not read package file " + packageFile); - //save to the installedPackages.config - var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); - _packagingService.SaveInstalledPackage(packageDefinition); +// //save to the installedPackages.config +// var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); +// _packagingService.SaveInstalledPackage(packageDefinition); - return Json(new - { - success = true, - packageId = packageDefinition.Id, - packageFile = packageInfo.PackageFileName, - percentage = 10, - message = "Downloading starter kit files..." - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// packageId = packageDefinition.Id, +// packageFile = packageInfo.PackageFileName, +// percentage = 10, +// message = "Downloading starter kit files..." +// }, HttpStatusCode.OK); +// } - /// - /// Installs the files in the package - /// - /// - [HttpPost] - public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) - { - model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); +// /// +// /// Installs the files in the package +// /// +// /// +// [HttpPost] +// public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) +// { +// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var definition = _packagingService.GetInstalledPackageById(model.PackageId); - if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); +// var definition = _packagingService.GetInstalledPackageById(model.PackageId); +// if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); - _packagingService.InstallCompiledPackageFiles(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); +// _packagingService.InstallCompiledPackageFiles(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - return Json(new - { - success = true, - ManifestId = model.PackageId, - model.PackageFile, - percentage = 20, - message = "Installing starter kit files" - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// ManifestId = model.PackageId, +// model.PackageFile, +// percentage = 20, +// message = "Installing starter kit files" +// }, HttpStatusCode.OK); +// } - /// - /// Ensures the app pool is restarted - /// - /// - [HttpPost] - public HttpResponseMessage RestartAppPool() - { - Current.RestartAppPool(Request.TryGetHttpContext().Result); - return Json(new - { - success = true, - percentage = 25, - message = "Installing starter kit files" - }, HttpStatusCode.OK); - } +// /// +// /// Ensures the app pool is restarted +// /// +// /// +// [HttpPost] +// public HttpResponseMessage RestartAppPool() +// { +// Current.RestartAppPool(Request.TryGetHttpContext().Result); +// return Json(new +// { +// success = true, +// percentage = 25, +// message = "Installing starter kit files" +// }, HttpStatusCode.OK); +// } - /// - /// Checks if the app pool has completed restarted - /// - /// - [HttpPost] - public HttpResponseMessage CheckAppPoolRestart() - { - if (Request.TryGetHttpContext().Result.Application.AllKeys.Contains("AppPoolRestarting")) - { - return Request.CreateResponse(HttpStatusCode.BadRequest); - } +// /// +// /// Checks if the app pool has completed restarted +// /// +// /// +// [HttpPost] +// public HttpResponseMessage CheckAppPoolRestart() +// { +// if (Request.TryGetHttpContext().Result.Application.AllKeys.Contains("AppPoolRestarting")) +// { +// return Request.CreateResponse(HttpStatusCode.BadRequest); +// } - return Json(new - { - percentage = 30, - success = true, - }, HttpStatusCode.OK); - } +// return Json(new +// { +// percentage = 30, +// success = true, +// }, HttpStatusCode.OK); +// } - /// - /// Installs the business logic portion of the package after app restart - /// - /// - [HttpPost] - public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) - { - model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); +// /// +// /// Installs the business logic portion of the package after app restart +// /// +// /// +// [HttpPost] +// public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) +// { +// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var definition = _packagingService.GetInstalledPackageById(model.PackageId); - if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); +// var definition = _packagingService.GetInstalledPackageById(model.PackageId); +// if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); - _packagingService.InstallCompiledPackageData(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); +// _packagingService.InstallCompiledPackageData(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - return Json(new - { - success = true, - ManifestId = model.PackageId, - model.PackageFile, - percentage = 70, - message = "Installing starter kit files" - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// ManifestId = model.PackageId, +// model.PackageFile, +// percentage = 70, +// message = "Installing starter kit files" +// }, HttpStatusCode.OK); +// } - /// - /// Cleans up the package installation - /// - /// - [HttpPost] - public HttpResponseMessage CleanupInstallation(InstallPackageModel model) - { - model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); +// /// +// /// Cleans up the package installation +// /// +// /// +// [HttpPost] +// public HttpResponseMessage CleanupInstallation(InstallPackageModel model) +// { +// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - return Json(new - { - success = true, - ManifestId = model.PackageId, - model.PackageFile, - percentage = 100, - message = "Starter kit has been installed" - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// ManifestId = model.PackageId, +// model.PackageFile, +// percentage = 100, +// message = "Starter kit has been installed" +// }, HttpStatusCode.OK); +// } - private HttpResponseMessage Json(object jsonObject, HttpStatusCode status) - { - var response = Request.CreateResponse(status); - var json = JObject.FromObject(jsonObject); - response.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json"); - return response; - } - } +// private HttpResponseMessage Json(object jsonObject, HttpStatusCode status) +// { +// var response = Request.CreateResponse(status); +// var json = JObject.FromObject(jsonObject); +// response.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json"); +// return response; +// } +// } -} +//} diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index 08a552d4d4..36fb384655 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -41,31 +41,6 @@ namespace Umbraco.Web.Install return _installationType ?? (_installationType = IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value; } - internal static void DeleteLegacyInstaller() - { - if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Install))) - { - if (Directory.Exists(IOHelper.MapPath("~/app_data/temp/install_backup"))) - { - //this means the backup already exists with files but there's no files in it, so we'll delete the backup and re-run it - if (Directory.GetFiles(IOHelper.MapPath("~/app_data/temp/install_backup")).Any() == false) - { - Directory.Delete(IOHelper.MapPath("~/app_data/temp/install_backup"), true); - Directory.Move(IOHelper.MapPath(SystemDirectories.Install), IOHelper.MapPath("~/app_data/temp/install_backup")); - } - } - else - { - Directory.Move(IOHelper.MapPath(SystemDirectories.Install), IOHelper.MapPath("~/app_data/temp/install_backup")); - } - } - - if (Directory.Exists(IOHelper.MapPath("~/Areas/UmbracoInstall"))) - { - Directory.Delete(IOHelper.MapPath("~/Areas/UmbracoInstall"), true); - } - } - internal void InstallStatus(bool isCompleted, string errorMsg) { try diff --git a/src/Umbraco.Web/Install/InstallStatusTracker.cs b/src/Umbraco.Web/Install/InstallStatusTracker.cs index 7944100648..d93eb9a06c 100644 --- a/src/Umbraco.Web/Install/InstallStatusTracker.cs +++ b/src/Umbraco.Web/Install/InstallStatusTracker.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Install private static string GetFile(Guid installId) { - var file = IOHelper.MapPath("~/App_Data/TEMP/Install/" + var file = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "Install/" + "install_" + installId.ToString("N") + ".txt"); @@ -39,7 +39,7 @@ namespace Umbraco.Web.Install public static void ClearFiles() { - var dir = IOHelper.MapPath("~/App_Data/TEMP/Install/"); + var dir = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "Install/"); if (Directory.Exists(dir)) { var files = Directory.GetFiles(dir); diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 0fe1e333d3..0349bb4ec7 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Web; @@ -49,39 +50,38 @@ namespace Umbraco.Web.Install.InstallSteps return null; } - var result = await DownloadPackageFilesAsync(starterKitId.Value); + var (packageFile, packageId) = await DownloadPackageFilesAsync(starterKitId.Value); Current.RestartAppPool(); return new InstallSetupResult(new Dictionary { - {"packageId", result.Item2}, - {"packageFile", result.Item1} + {"packageId", packageId}, + {"packageFile", packageFile} }); } - private async Task> DownloadPackageFilesAsync(Guid kitGuid) + private async Task<(string packageFile, int packageId)> DownloadPackageFilesAsync(Guid kitGuid) { //Go get the package file from the package repo - var packageFileName = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); - if (packageFileName == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); + var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); + if (packageFile == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); //add an entry to the installedPackages.config - var compiledPackage = _packageService.GetCompiledPackageInfo(packageFileName); + var compiledPackage = _packageService.GetCompiledPackageInfo(packageFile); var packageDefinition = PackageDefinition.FromCompiledPackage(compiledPackage); _packageService.SaveInstalledPackage(packageDefinition); - InstallPackageFiles(packageDefinition, compiledPackage.PackageFileName); + InstallPackageFiles(packageDefinition, compiledPackage.PackageFile); - return new Tuple(compiledPackage.PackageFileName, packageDefinition.Id); + return (compiledPackage.PackageFile.Name, packageDefinition.Id); } - private void InstallPackageFiles(PackageDefinition packageDefinition, string packageFileName) + private void InstallPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); - packageFileName = HttpUtility.UrlDecode(packageFileName); - _packageService.InstallCompiledPackageData(packageDefinition, packageFileName, _umbracoContext.Security.GetUserId().ResultOr(0)); + _packageService.InstallCompiledPackageData(packageDefinition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); } public override string View => _packageService.GetAllInstalledPackages().Any() ? string.Empty : base.View; diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 9d3f38b061..805041391f 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Web; @@ -30,22 +31,21 @@ namespace Umbraco.Web.Install.InstallSteps var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "StarterKitDownload"); var packageId = Convert.ToInt32(previousStep.AdditionalData["packageId"]); - var packageFile = (string)previousStep.AdditionalData["packageFile"]; - InstallBusinessLogic(packageId, packageFile); + InstallBusinessLogic(packageId); Current.RestartAppPool(_httContext); return Task.FromResult(null); } - private void InstallBusinessLogic(int packageId, string packageFile) + private void InstallBusinessLogic(int packageId) { - packageFile = HttpUtility.UrlDecode(packageFile); - var definition = _packagingService.GetInstalledPackageById(packageId); if (definition == null) throw new InvalidOperationException("Not package definition found with id " + packageId); + var packageFile = new FileInfo(definition.PackagePath); + _packagingService.InstallCompiledPackageData(definition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); } diff --git a/src/Umbraco.Web/Models/ContentTypeImportModel.cs b/src/Umbraco.Web/Models/ContentTypeImportModel.cs index 961476e5f0..f6f9a5926d 100644 --- a/src/Umbraco.Web/Models/ContentTypeImportModel.cs +++ b/src/Umbraco.Web/Models/ContentTypeImportModel.cs @@ -1,17 +1,13 @@ using System.Collections.Generic; using System.Runtime.Serialization; +using Umbraco.Core.Models.Editors; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models { [DataContract(Name = "contentTypeImportModel")] - public class ContentTypeImportModel : INotificationModel + public class ContentTypeImportModel : INotificationModel, IHaveUploadedFiles { - public ContentTypeImportModel() - { - Notifications = new List(); - } - [DataMember(Name = "alias")] public string Alias { get; set; } @@ -19,9 +15,11 @@ namespace Umbraco.Web.Models public string Name { get; set; } [DataMember(Name = "notifications")] - public List Notifications { get; } + public List Notifications { get; } = new List(); [DataMember(Name = "tempFileName")] public string TempFileName { get; set; } + + public List UploadedFiles => new List(); } } diff --git a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs index d1d51e1fcc..8adc9acf30 100644 --- a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs +++ b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs @@ -11,16 +11,10 @@ namespace Umbraco.Web.Models [DataContract(Name = "localPackageInstallModel")] public class LocalPackageInstallModel : PackageInstallModel, IHaveUploadedFiles, INotificationModel { - public LocalPackageInstallModel() - { - UploadedFiles = new List(); - Notifications = new List(); - } - - public List UploadedFiles { get; } + public List UploadedFiles { get; } = new List(); [DataMember(Name = "notifications")] - public List Notifications { get; } + public List Notifications { get; } = new List(); /// /// A flag to determine if this package is compatible to be installed diff --git a/src/Umbraco.Web/Models/PackageInstallModel.cs b/src/Umbraco.Web/Models/PackageInstallModel.cs index 1cf4a483ae..2decaeb098 100644 --- a/src/Umbraco.Web/Models/PackageInstallModel.cs +++ b/src/Umbraco.Web/Models/PackageInstallModel.cs @@ -15,13 +15,13 @@ namespace Umbraco.Web.Models [DataMember(Name = "packageGuid")] public Guid PackageGuid { get; set; } - //TODO: Do we need this? - [DataMember(Name = "repositoryGuid")] - public Guid RepositoryGuid { get; set; } + ////TODO: Do we need this? + //[DataMember(Name = "repositoryGuid")] + //public Guid RepositoryGuid { get; set; } - [DataMember(Name = "zipFilePath")] - public string ZipFilePath { get; set; } + [DataMember(Name = "zipFileName")] + public string ZipFileName { get; set; } /// /// During installation this can be used to track any pending appdomain restarts diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 0199a34579..422b502f80 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Components; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Profiling; using Umbraco.Core.Services; @@ -77,8 +78,6 @@ namespace Umbraco.Web.Runtime // Disable the X-AspNetMvc-Version HTTP Header MvcHandler.DisableMvcResponseHeader = true; - InstallHelper.DeleteLegacyInstaller(); - // wrap view engines in the profiling engine WrapViewEngines(ViewEngines.Engines); @@ -245,7 +244,7 @@ namespace Umbraco.Web.Runtime private static void ConfigureClientDependency(IGlobalSettings globalSettings) { // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] - XmlFileMapper.FileMapDefaultFolder = "~/App_Data/TEMP/ClientDependency"; + XmlFileMapper.FileMapDefaultFolder = SystemDirectories.TempData.EnsureEndsWith('/') + "ClientDependency"; BaseCompositeFileProcessingProvider.UrlTypeDefault = CompositeUrlType.Base64QueryStrings; // Now we need to detect if we are running umbracoLocalTempStorage as EnvironmentTemp and in that case we want to change the CDF file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 89260e59f6..36550f9b54 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1132,7 +1132,6 @@ - diff --git a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs index b60545e3cb..233ce39e52 100644 --- a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs @@ -14,7 +14,7 @@ using File = System.IO.File; namespace Umbraco.Web.WebApi.Filters { /// - /// Checks if the parameter is ContentItemSave and then deletes any temporary saved files from file uploads associated with the request + /// Checks if the parameter is IHaveUploadedFiles and then deletes any temporary saved files from file uploads associated with the request /// internal sealed class FileUploadCleanupFilterAttribute : ActionFilterAttribute { @@ -29,14 +29,6 @@ namespace Umbraco.Web.WebApi.Filters _incomingModel = incomingModel; } - /// - /// Returns true so that other filters can execute along with this one - /// - public override bool AllowMultiple - { - get { return true; } - } - public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); @@ -47,8 +39,7 @@ namespace Umbraco.Web.WebApi.Filters { if (actionExecutedContext.ActionContext.ActionArguments.Any()) { - var contentItem = actionExecutedContext.ActionContext.ActionArguments.First().Value as IHaveUploadedFiles; - if (contentItem != null) + if (actionExecutedContext.ActionContext.ActionArguments.First().Value is IHaveUploadedFiles contentItem) { //cleanup any files associated foreach (var f in contentItem.UploadedFiles) @@ -104,8 +95,7 @@ namespace Umbraco.Web.WebApi.Filters if (objectContent != null) { - var uploadedFiles = objectContent.Value as IHaveUploadedFiles; - if (uploadedFiles != null) + if (objectContent.Value is IHaveUploadedFiles uploadedFiles) { if (uploadedFiles.UploadedFiles != null) { diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs index 75614f68aa..26116820e6 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// This class implements the IPackageAction Interface, used to execute code when packages are installed. /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. /// - public class addApplication : IPackageAction + public class AddApplication : IPackageAction { #region IPackageAction Members diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs b/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs deleted file mode 100644 index 1e2e396d2c..0000000000 --- a/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Linq; -using System.Xml; -using System.Xml.Linq; -using System.Xml.XPath; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Xml; -using Umbraco.Core._Legacy.PackageActions; - -namespace Umbraco.Web._Legacy.PackageActions -{ - /// - /// - /// - public class addDashboardSection : IPackageAction - { - #region IPackageAction Members - - /// - /// Installs a dashboard section. This action reuses the action XML, so it has to be valid dashboard markup. - /// - /// Name of the package. - /// The XML data. - /// true if successfull - /// - /// - /// - ///
- /// - /// default - /// content - /// - /// - /// /usercontrols/dashboard/latestEdits.ascx - /// /usercontrols/umbracoBlog/dashboardBlogPostCreate.ascx - /// - /// - /// /usercontrols/umbracoBlog/dashboardBlogPostCreate.ascx - /// - ///
- ///
- ///
- ///
- public bool Execute(string packageName, XElement xmlData) - { - //this will need a complete section node to work... - - if (xmlData.HasElements) - { - string sectionAlias = xmlData.AttributeValue("dashboardAlias"); - string dbConfig = SystemFiles.DashboardConfig; - - var section = xmlData.Element("section"); - var dashboardFile = XDocument.Load(IOHelper.MapPath(dbConfig)); - - //don't continue if it already exists - var found = dashboardFile.XPathSelectElements("//section[@alias='" + sectionAlias + "']"); - if (!found.Any()) - { - dashboardFile.Root.Add(section); - dashboardFile.Save(IOHelper.MapPath(dbConfig)); - } - - return true; - } - - return false; - } - - - public string Alias() - { - return "addDashboardSection"; - } - - public bool Undo(string packageName, XElement xmlData) - { - - string sectionAlias = xmlData.AttributeValue("dashboardAlias"); - string dbConfig = SystemFiles.DashboardConfig; - var dashboardFile = XDocument.Load(IOHelper.MapPath(dbConfig)); - - var section = dashboardFile.XPathSelectElement("//section [@alias = '" + sectionAlias + "']"); - - if (section != null) - { - section.Remove(); - dashboardFile.Save(IOHelper.MapPath(dbConfig)); - } - - return true; - } - - #endregion - - } -} diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs b/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs index bcd7d7c52f..f53adb3be0 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs @@ -7,7 +7,7 @@ using Umbraco.Core._Legacy.PackageActions; namespace Umbraco.Web._Legacy.PackageActions { - public class addProxyFeedHost : IPackageAction + public class AddProxyFeedHost : IPackageAction { #region IPackageAction Members diff --git a/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs b/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs index 2ed16e3842..f4b206a9ad 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// This class implements the IPackageAction Interface, used to execute code when packages are installed. /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. ///
- public class allowDoctype : IPackageAction + public class AllowDoctype : IPackageAction { #region IPackageAction Members @@ -68,7 +68,6 @@ namespace Umbraco.Web._Legacy.PackageActions return false; } - //this has no undo. /// /// This action has no undo. /// diff --git a/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs b/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs index f4fe17e999..f4bd7dd4fc 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// This class implements the IPackageAction Interface, used to execute code when packages are installed. /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. ///
- public class publishRootDocument : IPackageAction + public class PublishRootDocument : IPackageAction { #region IPackageAction Members @@ -29,7 +29,6 @@ namespace Umbraco.Web._Legacy.PackageActions string documentName = xmlData.AttributeValue("documentName"); - //global::umbraco.cms.businesslogic.web.Document[] rootDocs = global::umbraco.cms.businesslogic.web.Document.GetRootDocuments(); var rootDocs = Current.Services.ContentService.GetRootContent(); foreach (var rootDoc in rootDocs) @@ -44,7 +43,6 @@ namespace Umbraco.Web._Legacy.PackageActions return true; } - //this has no undo. /// /// This action has no undo. /// From 5b1ca92184fa9962a7306f0db09ac36c37d5f777 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 12:12:35 +0100 Subject: [PATCH 092/223] Fixes for tag validation and build --- .../components/tags/umbtagseditor.directive.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index 92c9d57ee8..3d784c999f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -181,7 +181,7 @@ else { vm.onValueChanged({ value: [] }); } - + reValidate(); } @@ -190,7 +190,7 @@ */ function validateMandatory() { return { - isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0), + isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0)|| (vm.value != null && vm.value.length > 0), errorMsg: "Value cannot be empty", errorKey: "required" }; @@ -271,12 +271,12 @@ return ($.inArray(suggestion.value, vm.viewModel) === -1); }); } - + function reValidate() { //this is required to re-validate vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length); - { - + } + } })(); From a5efc25c8152db9a4d38b138a0e3f46c9cc5ea93 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 12:23:14 +0100 Subject: [PATCH 093/223] Revert "Support IContentType.IsElement" This reverts commit ba38b67b --- .../services/umbdataformatter.service.js | 18 +++++++-------- .../permissions/permissions.controller.js | 22 ++++++++++++------- .../views/permissions/permissions.html | 20 ++--------------- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 -- .../Umbraco/config/lang/en_us.xml | 2 -- .../ContentTypeCompositionDisplay.cs | 4 ---- .../Models/ContentEditing/ContentTypeSave.cs | 3 --- 7 files changed, 25 insertions(+), 46 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index 1e6fc5d643..e31742e660 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -64,7 +64,7 @@ var saveModel = _.pick(displayModel, 'compositeContentTypes', 'isContainer', 'allowAsRoot', 'allowedTemplates', 'allowedContentTypes', 'alias', 'description', 'thumbnail', 'name', 'id', 'icon', 'trashed', - 'key', 'parentId', 'alias', 'path', 'allowCultureVariant', 'isElement'); + 'key', 'parentId', 'alias', 'path', 'allowCultureVariant'); //TODO: Map these saveModel.allowedTemplates = _.map(displayModel.allowedTemplates, function (t) { return t.alias; }); @@ -262,7 +262,7 @@ saveModel[props[m]] = startId.id; } - saveModel.parentId = -1; + saveModel.parentId = -1; return saveModel; }, @@ -293,7 +293,7 @@ }); saveModel.email = propEmail.value.trim(); saveModel.username = propLogin.value.trim(); - + saveModel.password = this.formatChangePasswordModel(propPass.value); var selectedGroups = []; @@ -336,7 +336,7 @@ /** formats the display model used to display the media to the model used to save the media */ formatMediaPostData: function (displayModel, action) { - //NOTE: the display model inherits from the save model so we can in theory just post up the display model but + //NOTE: the display model inherits from the save model so we can in theory just post up the display model but // we don't want to post all of the data as it is unecessary. var saveModel = { id: displayModel.id, @@ -354,7 +354,7 @@ /** formats the display model used to display the content to the model used to save the content */ formatContentPostData: function (displayModel, action) { - //NOTE: the display model inherits from the save model so we can in theory just post up the display model but + //NOTE: the display model inherits from the save model so we can in theory just post up the display model but // we don't want to post all of the data as it is unecessary. var saveModel = { id: displayModel.id, @@ -379,7 +379,7 @@ var propExpireDate = displayModel.removeDate; var propReleaseDate = displayModel.releaseDate; var propTemplate = displayModel.template; - + saveModel.expireDate = propExpireDate ? propExpireDate : null; saveModel.releaseDate = propReleaseDate ? propReleaseDate : null; saveModel.templateAlias = propTemplate ? propTemplate : null; @@ -389,8 +389,8 @@ /** * This formats the server GET response for a content display item - * @param {} displayModel - * @returns {} + * @param {} displayModel + * @returns {} */ formatContentGetData: function(displayModel) { @@ -418,7 +418,7 @@ } }); }); - + //now assign this same invariant property instance to the same index of the other variants property array for (var j = 1; j < displayModel.variants.length; j++) { diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js index 317fe094ae..4a7a870618 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js @@ -25,7 +25,6 @@ vm.removeChild = removeChild; vm.toggleAllowAsRoot = toggleAllowAsRoot; vm.toggleAllowCultureVariants = toggleAllowCultureVariants; - vm.toggleIsElement = toggleIsElement; /* ---------- INIT ---------- */ @@ -85,18 +84,25 @@ $scope.model.allowedContentTypes.splice(selectedChildIndex, 1); } - // note: "safe toggling" here ie handling cases where the value is undefined, etc + /** + * Toggle the $scope.model.allowAsRoot value to either true or false + */ + function toggleAllowAsRoot(){ + if($scope.model.allowAsRoot){ + $scope.model.allowAsRoot = false; + return; + } - function toggleAllowAsRoot() { - $scope.model.allowAsRoot = $scope.model.allowAsRoot ? false : true; + $scope.model.allowAsRoot = true; } function toggleAllowCultureVariants() { - $scope.model.allowCultureVariant = $scope.model.allowCultureVariant ? false : true; - } + if ($scope.model.allowCultureVariant) { + $scope.model.allowCultureVariant = false; + return; + } - function toggleIsElement() { - $scope.model.isElement = $scope.model.isElement ? false : true; + $scope.model.allowCultureVariant = true; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html index 0d74c655d7..ec1e528f8c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html @@ -53,25 +53,9 @@ hotkey="alt+shift+v"> - + -
- -
-
- -
- -
- - -
- -
- - + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 987203442a..386d3af518 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1518,8 +1518,6 @@ To manage your website, simply open the Umbraco back office and start adding con Allow varying by culture Allow editors to create content of this type in different languages Allow varying by culture - Is an Element type - An Element type is meant to be used for instance in Nested Content, and not in the tree Building models 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 1860d3afc9..5de373f571 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1559,8 +1559,6 @@ To manage your website, simply open the Umbraco back office and start adding con Allow varying by culture Allow editors to create content of this type in different languages Allow varying by culture - Is an Element type - An Element type is meant to be used for instance in Nested Content, and not in the tree Add language diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs index e5e74c2749..7211ddbf61 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs @@ -26,10 +26,6 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } - //Element - [DataMember(Name = "isElement")] - public bool IsElement { get; set; } - [DataMember(Name = "listViewEditorName")] [ReadOnly(true)] public string ListViewEditorName { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs index b1d24c5fd2..c2ec70d3dc 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs @@ -25,9 +25,6 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } - [DataMember(Name = "isElement")] - public bool IsElement { get; set; } - [DataMember(Name = "allowAsRoot")] public bool AllowAsRoot { get; set; } From ff6a9ba97f17bddd64edb1da5cc0a8858fb336f9 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 12:23:45 +0100 Subject: [PATCH 094/223] Revert "Identify element types" This reverts commit 4ad2505b --- .../Migrations/Upgrade/UmbracoPlan.cs | 1 - .../V_8_0_0/AddContentTypeIsElementColumn.cs | 15 ---------- src/Umbraco.Core/Models/ContentTypeBase.cs | 10 ------- .../Models/ContentTypeBaseExtensions.cs | 3 +- src/Umbraco.Core/Models/IContentTypeBase.cs | 12 +------- .../PublishedContent/PublishedItemType.cs | 7 +---- .../Persistence/Dtos/ContentTypeDto.cs | 4 --- .../Factories/ContentTypeFactory.cs | 2 -- .../Persistence/Mappers/ContentTypeMapper.cs | 1 - .../Persistence/Mappers/MediaTypeMapper.cs | 1 - .../Persistence/Mappers/MemberTypeMapper.cs | 1 - .../Implement/ContentTypeRepositoryBase.cs | 6 ++-- .../Services/EntityXmlSerializer.cs | 3 +- .../Services/Implement/PackagingService.cs | 4 --- src/Umbraco.Core/Umbraco.Core.csproj | 1 - .../PublishedContent/PublishedContentTests.cs | 1 + .../Services/ContentTypeServiceTests.cs | 30 ------------------- .../ContentEditing/ContentItemDisplay.cs | 8 +---- .../Models/Mapping/ContentMapperProfile.cs | 5 ++-- 19 files changed, 10 insertions(+), 105 deletions(-) delete mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 9ec970f1fe..b469c02a3c 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -121,7 +121,6 @@ namespace Umbraco.Core.Migrations.Upgrade To("{648A2D5F-7467-48F8-B309-E99CEEE00E2A}"); // fixed version To("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}"); To("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}"); - To("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}"); //FINAL diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs deleted file mode 100644 index 1df11a3e99..0000000000 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Umbraco.Core.Persistence.Dtos; - -namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 -{ - public class AddContentTypeIsElementColumn : MigrationBase - { - public AddContentTypeIsElementColumn(IMigrationContext context) : base(context) - { } - - public override void Migrate() - { - AddColumn("isElement"); - } - } -} diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index b6ea9f50a0..88b1179f6d 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -26,7 +26,6 @@ namespace Umbraco.Core.Models private string _thumbnail = "folder.png"; private bool _allowedAsRoot; // note: only one that's not 'pure element type' private bool _isContainer; - private bool _isElement; private PropertyGroupCollection _propertyGroups; private PropertyTypeCollection _noGroupPropertyTypes; private IEnumerable _allowedContentTypes; @@ -91,7 +90,6 @@ namespace Umbraco.Core.Models public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon); public readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.Thumbnail); public readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot); - public readonly PropertyInfo IsElementSelector = ExpressionHelper.GetPropertyInfo(x => x.IsElement); public readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer); public readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes); public readonly PropertyInfo PropertyGroupsSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups); @@ -182,14 +180,6 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _isContainer, Ps.Value.IsContainerSelector); } - /// - [DataMember] - public bool IsElement - { - get => _isElement; - set => SetPropertyValueAndDetectChanges(value, ref _isElement, Ps.Value.IsElementSelector); - } - /// /// Gets or sets a list of integer Ids for allowed ContentTypes /// diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs index adbc3de54f..8af48bb881 100644 --- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs @@ -15,8 +15,7 @@ namespace Umbraco.Core.Models { var type = contentType.GetType(); var itemType = PublishedItemType.Unknown; - if (contentType.IsElement) itemType = PublishedItemType.Element; - else if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content; + if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content; else if (typeof(IMediaType).IsAssignableFrom(type)) itemType = PublishedItemType.Media; else if (typeof(IMemberType).IsAssignableFrom(type)) itemType = PublishedItemType.Member; return itemType; diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index 787e347b37..a1d4aee02f 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Models /// the icon (eg. icon-home) along with an optional CSS class name representing the /// color (eg. icon-blue). Put together, the value for this scenario would be /// icon-home color-blue. - /// + /// /// If a class name for the color isn't specified, the icon color will default to black. ///
string Icon { get; set; } @@ -48,16 +48,6 @@ namespace Umbraco.Core.Models /// bool IsContainer { get; set; } - /// - /// Gets or sets a value indicating whether this content type is for an element. - /// - /// - /// By default a content type is for a true media, member or document, but - /// it can also be for an element, ie a subset that can for instance be used in - /// nested content. - /// - bool IsElement { get; set; } - /// /// Gets or sets the content variation of the content type. /// diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs index 42e9c9538d..e55fe66945 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs @@ -4,18 +4,13 @@ /// The type of published element. ///
/// Can be a simple element, or a document, a media, a member. - public enum PublishedItemType + public enum PublishedItemType // fixme - need to rename to PublishedElementType but then conflicts? { /// /// Unknown. /// Unknown = 0, - /// - /// An element. - /// - Element, - /// /// A document. /// diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs index 4f3a67aa91..d930abc54c 100644 --- a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs @@ -41,10 +41,6 @@ namespace Umbraco.Core.Persistence.Dtos [Constraint(Default = "0")] public bool IsContainer { get; set; } - [Column("isElement")] - [Constraint(Default = "0")] - public bool IsElement { get; set; } - [Column("allowAtRoot")] [Constraint(Default = "0")] public bool AllowAtRoot { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs index 7a04a6d0d9..38a1aa2aab 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs @@ -107,7 +107,6 @@ namespace Umbraco.Core.Persistence.Factories entity.CreatorId = dto.NodeDto.UserId ?? Constants.Security.UnknownUserId; entity.AllowedAsRoot = dto.AllowAtRoot; entity.IsContainer = dto.IsContainer; - entity.IsElement = dto.IsElement; entity.Trashed = dto.NodeDto.Trashed; entity.Variations = (ContentVariation) dto.Variations; } @@ -133,7 +132,6 @@ namespace Umbraco.Core.Persistence.Factories NodeId = entity.Id, AllowAtRoot = entity.AllowedAsRoot, IsContainer = entity.IsContainer, - IsElement = entity.IsElement, Variations = (byte) entity.Variations, NodeDto = BuildNodeDto(entity, nodeObjectType) }; diff --git a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs index a24963bace..c692a75474 100644 --- a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs @@ -35,7 +35,6 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); - CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs index 6cf83bc7aa..3f5a6e24bc 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs @@ -35,7 +35,6 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); - CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs index 9a4e4ec040..28dc19171f 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs @@ -35,7 +35,6 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); - CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 683df047f8..662254d1ee 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1283,7 +1283,7 @@ AND umbracoNode.id <> @id", if (db == null) throw new ArgumentNullException(nameof(db)); var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations, - cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey, umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, @@ -1384,7 +1384,6 @@ AND umbracoNode.id <> @id", Description = currCt.ctDesc, Icon = currCt.ctIcon, IsContainer = currCt.ctIsContainer, - IsElement = currCt.ctIsElement, NodeId = currCt.ctId, PrimaryKey = currCt.ctPk, Thumbnail = currCt.ctThumb, @@ -1423,7 +1422,7 @@ AND umbracoNode.id <> @id", var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId, cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations, - cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey, umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, @@ -1560,7 +1559,6 @@ AND umbracoNode.id <> @id", Description = currCt.ctDesc, Icon = currCt.ctIcon, IsContainer = currCt.ctIsContainer, - IsElement = currCt.ctIsElement, NodeId = currCt.ctId, PrimaryKey = currCt.ctPk, Thumbnail = currCt.ctThumb, diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 38d5471bb7..d938e032a8 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -337,8 +337,7 @@ namespace Umbraco.Core.Services new XElement("Thumbnail", contentType.Thumbnail), new XElement("Description", contentType.Description), new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()), - new XElement("IsListView", contentType.IsContainer.ToString()), - new XElement("IsElement", contentType.IsElement.ToString())); + new XElement("IsListView", contentType.IsContainer.ToString())); var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId); if(masterContentType != null) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 8f6c287cf1..106d2b9f12 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -578,10 +578,6 @@ namespace Umbraco.Core.Services.Implement if (isListView != null) contentType.IsContainer = isListView.Value.InvariantEquals("true"); - var isElement = infoElement.Element("IsElement"); - if (isListView != null) - contentType.IsElement = isElement.Value.InvariantEquals("true"); - //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set var masterElement = infoElement.Element("Master"); if (masterElement != null) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7d65a46f49..609befd233 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -377,7 +377,6 @@ - diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index ab65ac82b1..914956dce1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -233,6 +233,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("Fails as long as PublishedContentModel is internal.")] // fixme public void Is_Last_From_Where_Filter2() { var doc = GetNode(1173); diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 8dc8a2b45c..b1a8fa26a8 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -22,36 +22,6 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] public class ContentTypeServiceTests : TestWithSomeContentBase { - [Test] - public void CanSaveAndGetIsElement() - { - //create content type with a property type that varies by culture - IContentType contentType = MockedContentTypes.CreateBasicContentType(); - contentType.Variations = ContentVariation.Nothing; - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) - { - Alias = "title", - Name = "Title", - Description = "", - Mandatory = false, - SortOrder = 1, - DataTypeId = -88, - Variations = ContentVariation.Nothing - }); - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - ServiceContext.ContentTypeService.Save(contentType); - - contentType = ServiceContext.ContentTypeService.Get(contentType.Id); - Assert.IsFalse(contentType.IsElement); - - contentType.IsElement = true; - ServiceContext.ContentTypeService.Save(contentType); - - contentType = ServiceContext.ContentTypeService.Get(contentType.Id); - Assert.IsTrue(contentType.IsElement); - } - [Test] public void Change_Content_Type_Variation_Clears_Redirects() { diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index 80358bfc7a..4908025351 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -86,12 +86,6 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } - /// - /// Indicates if the content is configured as an element - /// - [DataMember(Name = "isElement")] - public bool IsElement { get; set; } - /// /// Property indicating if this item is part of a list view parent /// @@ -123,7 +117,7 @@ namespace Umbraco.Web.Models.ContentEditing /// [DataMember(Name = "updateDate")] public DateTime UpdateDate { get; set; } - + [DataMember(Name = "template")] public string TemplateAlias { get; set; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs index 1caf81a1eb..6de3bdc02c 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs @@ -46,7 +46,6 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name)) .ForMember(dest => dest.IsContainer, opt => opt.MapFrom(src => src.ContentType.IsContainer)) - .ForMember(dest => dest.IsElement, opt => opt.MapFrom(src => src.ContentType.IsElement)) .ForMember(dest => dest.IsBlueprint, opt => opt.MapFrom(src => src.Blueprint)) .ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) @@ -60,7 +59,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.AllowedTemplates, opt => opt.MapFrom(content => content.ContentType.AllowedTemplates .Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false) - .ToDictionary(t => t.Alias, t => t.Name))) + .ToDictionary(t => t.Alias, t => t.Name))) .ForMember(dest => dest.AllowedActions, opt => opt.ResolveUsing(src => actionButtonsResolver.Resolve(src))) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); @@ -141,5 +140,5 @@ namespace Umbraco.Web.Models.Mapping return source.CultureInfos.TryGetValue(culture, out var name) && !name.Name.IsNullOrWhiteSpace() ? name.Name : $"(({source.Name}))"; } } - } + } } From a5ff29ccc7457ecb7ea82744e405daf58cdc2d57 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 15 Jan 2019 22:59:13 +1100 Subject: [PATCH 095/223] Gets package uninstall working, fixes other UI issues with packages --- .../Packaging/CompiledPackageXmlParser.cs | 37 ++-- .../Packaging/PackageDefinitionXmlParser.cs | 2 + .../Packaging/PackageInstallation.cs | 1 + .../src/views/packages/overview.controller.js | 15 +- .../src/views/packages/overview.html | 34 ++- .../views/install-local.controller.js | 2 +- .../packages/views/installed.controller.js | 16 +- .../Controllers/InstallPackageController.cs | 196 ------------------ src/Umbraco.Web/Install/UmbracoInstallArea.cs | 8 - 9 files changed, 67 insertions(+), 244 deletions(-) delete mode 100644 src/Umbraco.Web/Install/Controllers/InstallPackageController.cs diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index eb9cf46008..be9c69667a 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -149,37 +149,50 @@ namespace Umbraco.Core.Packaging return path; } + /// + /// Parses the package actions stored in the package definition + /// + /// + /// + /// public IEnumerable GetPackageActions(XElement actionsElement, string packageName) { - if (actionsElement == null) { return new PackageAction[0]; } + if (actionsElement == null) return Enumerable.Empty(); - if (string.Equals("Actions", actionsElement.Name.LocalName) == false) - throw new ArgumentException($"Must be \"Actions\" as root", nameof(actionsElement)); + //invariant check ... because people can realy enter anything :/ + if (!string.Equals("actions", actionsElement.Name.LocalName, StringComparison.InvariantCultureIgnoreCase)) + throw new FormatException("Must be \"\" as root"); - return actionsElement.Elements("Action") - .Select(elemet => + if (!actionsElement.HasElements) return Enumerable.Empty(); + + var actionElementName = actionsElement.Elements().First().Name.LocalName; + + //invariant check ... because people can realy enter anything :/ + if (!string.Equals("action", actionElementName, StringComparison.InvariantCultureIgnoreCase)) + throw new FormatException("Must be \" { - var aliasAttr = elemet.Attribute("Alias"); + var aliasAttr = e.Attribute("alias") ?? e.Attribute("Alias"); //allow both ... because people can really enter anything :/ if (aliasAttr == null) - throw new ArgumentException("missing \"Alias\" atribute in alias element", nameof(actionsElement)); + throw new ArgumentException("missing \"alias\" atribute in alias element", nameof(actionsElement)); var packageAction = new PackageAction { - XmlData = elemet, + XmlData = e, Alias = aliasAttr.Value, PackageName = packageName, }; - - var attr = elemet.Attribute("runat"); + var attr = e.Attribute("runat") ?? e.Attribute("Runat"); //allow both ... because people can really enter anything :/ if (attr != null && Enum.TryParse(attr.Value, true, out ActionRunAt runAt)) { packageAction.RunAt = runAt; } - attr = elemet.Attribute("undo"); + attr = e.Attribute("undo") ?? e.Attribute("Undo"); //allow both ... because people can really enter anything :/ if (attr != null && bool.TryParse(attr.Value, out var undo)) { packageAction.Undo = undo; } - return packageAction; }).ToArray(); } diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 0d7adf8ece..45e6fd9845 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -105,5 +105,7 @@ namespace Umbraco.Core.Packaging return packageXml; } + + } } diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 4563d31560..7abf96b266 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -76,6 +76,7 @@ namespace Umbraco.Core.Packaging { //running this will update the PackageDefinition with the items being removed var summary = _packageDataInstallation.UninstallPackageData(package, userId); + summary.Actions = _parser.GetPackageActions(XElement.Parse(package.Actions), package.Name); //run actions before files are removed diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index 4ca0015aa5..ccd86c6f6c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesOverviewController($scope, $route, $location, navigationService, $timeout, localStorageService) { + function PackagesOverviewController($scope, $location, localStorageService) { //Hack! // if there is a cookie value for packageInstallUri then we need to redirect there, @@ -9,12 +9,13 @@ // because it will double load it. // we will refresh and then navigate there. - var installPackageUri = localStorageService.get("packageInstallUri"); - const packageUri = $location.search().subview; + let installPackageUri = localStorageService.get("packageInstallUri"); + let packageUri = $location.search().subview; if (installPackageUri) { localStorageService.remove("packageInstallUri"); } + if (installPackageUri && installPackageUri !== "installed") { //navigate to the custom installer screen, if it is just "installed", then we'll //show the installed view @@ -23,6 +24,8 @@ else { var vm = this; + packageUri = installPackageUri ? installPackageUri : packageUri; //use the path stored in storage over the one in the current path + vm.page = {}; vm.page.name = "Packages"; vm.page.navigation = [ @@ -30,7 +33,7 @@ "name": "Packages", "icon": "icon-cloud", "view": "views/packages/views/repo.html", - "active": !packageUri || installPackageUri === "navigation" || packageUri === "navigation", + "active": !packageUri || packageUri === "navigation", "alias": "umbPackages", "action": function() { $location.search("subview", "navigation"); @@ -40,7 +43,7 @@ "name": "Installed", "icon": "icon-box", "view": "views/packages/views/installed.html", - "active": installPackageUri === "installed" || packageUri === "installed", + "active": packageUri === "installed", "alias": "umbInstalled", "action": function() { $location.search("subview", "installed"); @@ -50,7 +53,7 @@ "name": "Install local", "icon": "icon-add", "view": "views/packages/views/install-local.html", - "active": installPackageUri === "local" || packageUri === "local", + "active": packageUri === "local", "alias": "umbInstallLocal", "action": function() { $location.search("subview", "local"); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.html b/src/Umbraco.Web.UI.Client/src/views/packages/overview.html index 250dc889d6..84f594b48d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.html @@ -1,28 +1,24 @@
-
+ - + + - - + - + + - - + - - - - - +
diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js index 9c6c2bb7c5..6753fad942 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesInstallLocalController($scope, $route, $location, Upload, umbRequestHelper, packageResource, localStorageService, $timeout, $window, localizationService, $q) { + function PackagesInstallLocalController($scope, Upload, umbRequestHelper, packageResource, localStorageService, $timeout, $window, localizationService, $q) { var vm = this; vm.state = "upload"; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js index ce1d2cca0f..6e0e162e86 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js @@ -13,6 +13,8 @@ }; vm.package = {}; + var labels = {}; + function init() { packageResource.getInstalled() .then(function (packs) { @@ -20,6 +22,16 @@ }); vm.installState.status = ""; vm.state = "list"; + + var labelKeys = [ + "packager_installStateUninstalling", + "packager_installStateComplete", + ]; + + localizationService.localizeMany(labelKeys).then(function (values) { + labels.installStateUninstalling = values[0]; + labels.installStateComplete = values[1]; + }); } function confirmUninstall(pck) { @@ -28,14 +40,14 @@ } function uninstallPackage(installedPackage) { - vm.installState.status = localizationService.localize("packager_installStateUninstalling"); + vm.installState.status = labels.installStateUninstalling; vm.installState.progress = "0"; packageResource.uninstall(installedPackage.id) .then(function () { if (installedPackage.files.length > 0) { - vm.installState.status = localizationService.localize("packager_installStateComplete"); + vm.installState.status = labels.installStateComplete; vm.installState.progress = "100"; //set this flag so that on refresh it shows the installed packages list diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs deleted file mode 100644 index 81cb1e2e39..0000000000 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ /dev/null @@ -1,196 +0,0 @@ -//using System; -//using System.Linq; -//using System.Net; -//using System.Net.Http; -//using System.Text; -//using System.Threading.Tasks; -//using System.Web; -//using System.Web.Http; -//using Newtonsoft.Json.Linq; -//using umbraco; -//using Umbraco.Core; -//using Umbraco.Web.Cache; -//using Umbraco.Core.Configuration; -//using Umbraco.Core.Models.Packaging; -//using Umbraco.Core.Services; -//using Umbraco.Web.Composing; -//using Umbraco.Web.Install.Models; -//using Umbraco.Web.WebApi; - -//namespace Umbraco.Web.Install.Controllers -//{ -// /// -// /// A controller for the installation process regarding packages -// /// -// /// -// /// Currently this is used for web services however we should/could eventually migrate the whole installer to MVC as it -// /// is a bit of a mess currently. -// /// -// [HttpInstallAuthorize] -// [AngularJsonOnlyConfiguration] -// [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] -// //fixme: Is this used anymore?? -// public class InstallPackageController : ApiController -// { -// private readonly IPackagingService _packagingService; -// private readonly UmbracoContext _umbracoContext; - -// public InstallPackageController(IPackagingService packagingService, UmbracoContext umbracoContext) -// { -// _packagingService = packagingService; -// _umbracoContext = umbracoContext; -// } - -// /// -// /// Empty action, useful for retrieving the base url for this controller -// /// -// /// -// [HttpGet] -// public HttpResponseMessage Index() -// { -// throw new NotImplementedException(); -// } - -// /// -// /// Connects to the repo, downloads the package and creates the definition -// /// -// /// -// /// -// [HttpPost] -// public async Task DownloadPackageFiles(InstallPackageModel model) -// { -// var packageFile = await _packagingService.FetchPackageFileAsync( -// model.KitGuid, -// UmbracoVersion.Current, -// UmbracoContext.Current.Security.CurrentUser.Id); - - -// var packageInfo = _packagingService.GetCompiledPackageInfo(packageFile); -// if (packageInfo == null) throw new InvalidOperationException("Could not read package file " + packageFile); - -// //save to the installedPackages.config -// var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); -// _packagingService.SaveInstalledPackage(packageDefinition); - -// return Json(new -// { -// success = true, -// packageId = packageDefinition.Id, -// packageFile = packageInfo.PackageFileName, -// percentage = 10, -// message = "Downloading starter kit files..." -// }, HttpStatusCode.OK); -// } - -// /// -// /// Installs the files in the package -// /// -// /// -// [HttpPost] -// public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) -// { -// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - -// var definition = _packagingService.GetInstalledPackageById(model.PackageId); -// if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); - -// _packagingService.InstallCompiledPackageFiles(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - -// return Json(new -// { -// success = true, -// ManifestId = model.PackageId, -// model.PackageFile, -// percentage = 20, -// message = "Installing starter kit files" -// }, HttpStatusCode.OK); -// } - -// /// -// /// Ensures the app pool is restarted -// /// -// /// -// [HttpPost] -// public HttpResponseMessage RestartAppPool() -// { -// Current.RestartAppPool(Request.TryGetHttpContext().Result); -// return Json(new -// { -// success = true, -// percentage = 25, -// message = "Installing starter kit files" -// }, HttpStatusCode.OK); -// } - -// /// -// /// Checks if the app pool has completed restarted -// /// -// /// -// [HttpPost] -// public HttpResponseMessage CheckAppPoolRestart() -// { -// if (Request.TryGetHttpContext().Result.Application.AllKeys.Contains("AppPoolRestarting")) -// { -// return Request.CreateResponse(HttpStatusCode.BadRequest); -// } - -// return Json(new -// { -// percentage = 30, -// success = true, -// }, HttpStatusCode.OK); -// } - -// /// -// /// Installs the business logic portion of the package after app restart -// /// -// /// -// [HttpPost] -// public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) -// { -// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - -// var definition = _packagingService.GetInstalledPackageById(model.PackageId); -// if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); - -// _packagingService.InstallCompiledPackageData(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - -// return Json(new -// { -// success = true, -// ManifestId = model.PackageId, -// model.PackageFile, -// percentage = 70, -// message = "Installing starter kit files" -// }, HttpStatusCode.OK); -// } - -// /// -// /// Cleans up the package installation -// /// -// /// -// [HttpPost] -// public HttpResponseMessage CleanupInstallation(InstallPackageModel model) -// { -// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - -// return Json(new -// { -// success = true, -// ManifestId = model.PackageId, -// model.PackageFile, -// percentage = 100, -// message = "Starter kit has been installed" -// }, HttpStatusCode.OK); -// } - -// private HttpResponseMessage Json(object jsonObject, HttpStatusCode status) -// { -// var response = Request.CreateResponse(status); -// var json = JObject.FromObject(jsonObject); -// response.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json"); -// return response; -// } -// } - -//} diff --git a/src/Umbraco.Web/Install/UmbracoInstallArea.cs b/src/Umbraco.Web/Install/UmbracoInstallArea.cs index 2b44abd4ab..398ed7b245 100644 --- a/src/Umbraco.Web/Install/UmbracoInstallArea.cs +++ b/src/Umbraco.Web/Install/UmbracoInstallArea.cs @@ -32,14 +32,6 @@ namespace Umbraco.Web.Install new { controller = "Install", action = "Index", id = UrlParameter.Optional }, new[] { typeof(InstallController).Namespace }); - //TODO: We can remove this when we re-build the back office package installer - //Create the install routes - context.MapHttpRoute( - "Umbraco_install_packages", - "Install/PackageInstaller/{action}/{id}", - new { controller = "InstallPackage", action = "Index", id = UrlParameter.Optional }, - new[] { typeof(InstallPackageController).Namespace }); - context.MapHttpRoute( "umbraco-install-api", "install/api/{action}/{id}", From 8c7d29bd020a62a2d87c2a34763ab4b865a01080 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 15 Jan 2019 23:03:23 +1100 Subject: [PATCH 096/223] file update missing --- src/Umbraco.Web/Umbraco.Web.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f8f33ca0fa..b0142771d2 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -730,7 +730,6 @@ - From 56ab88983a9c95d0803c348e989c23b0c2fc9124 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 15 Jan 2019 23:10:08 +1100 Subject: [PATCH 097/223] updates a test --- .../Packaging/PackageInstallation.cs | 6 +++++- .../Services/Implement/PackagingService.cs | 3 +-- .../Packaging/PackageInstallationTest.cs | 21 ++++--------------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 7abf96b266..ae9b8173f5 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -69,7 +69,11 @@ namespace Umbraco.Core.Packaging var packageZipFile = compiledPackage.PackageFile; - return _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _packageExtractionFolder.FullName); + var files = _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _packageExtractionFolder.FullName).ToList(); + + packageDefinition.Files = files; + + return files; } public UninstallationSummary UninstallPackage(PackageDefinition package, int userId) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 362b1fc67b..a5c279fa21 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -109,8 +109,7 @@ namespace Umbraco.Core.Services.Implement if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFile); var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId).ToList(); - packageDefinition.Files = files; - + SaveInstalledPackage(packageDefinition); _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package files installed for package '{compiledPackage.Name}'."); diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 7514eea00b..62feb64c10 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -1,16 +1,14 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -55,19 +53,6 @@ namespace Umbraco.Tests.Packaging private const string DocumentTypePickerUmb = "Document_Type_Picker_1.1.umb"; - //[Test] - //public void PackagingService_Can_ImportPackage() - //{ - // const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; - - // string testPackagePath = GetTestPackagePath(documentTypePickerUmb); - - // InstallationSummary installationSummary = packagingService.InstallPackage(testPackagePath); - - // Assert.IsNotNull(installationSummary); - //} - - [Test] public void Can_Read_Compiled_Package() { @@ -111,9 +96,11 @@ namespace Umbraco.Tests.Packaging var package = PackageInstallation.ReadPackage( //this is where our test zip file is new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); + var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); + def.Files = new List(); //clear out the files of the def for testing, this should be populated by the install var result = PackageInstallation.InstallPackageFiles(def, package, -1).ToList(); @@ -122,7 +109,7 @@ namespace Umbraco.Tests.Packaging Assert.IsTrue(File.Exists(Path.Combine(IOHelper.MapPath("~/" + _testBaseFolder), result[0]))); //make sure the def is updated too - Assert.AreEqual(result.Count(), def.Files.Count); + Assert.AreEqual(result.Count, def.Files.Count); } [Test] From 93ba694106d2f435126a495b8111df01ed3e43b8 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 13:36:30 +0100 Subject: [PATCH 098/223] Upgrade ModelsBuilder (bugfix) --- build/NuSpecs/UmbracoCms.nuspec | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index 565d693979..1b7a1c5ae1 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -22,7 +22,7 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 7a59b15eb3..ca4acd9d66 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -107,7 +107,7 @@ - 8.0.0-alpha.31 + 8.0.0-alpha.32 From 62fcbd8e84c8e6c09e1f4a7cef70d469ac6f43d3 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 13:43:56 +0100 Subject: [PATCH 099/223] Handle max runtime level for components --- src/Umbraco.Core/Components/Composers.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Components/Composers.cs b/src/Umbraco.Core/Components/Composers.cs index 1c836e9e5c..89deed934e 100644 --- a/src/Umbraco.Core/Components/Composers.cs +++ b/src/Umbraco.Core/Components/Composers.cs @@ -76,11 +76,13 @@ namespace Umbraco.Core.Components var composerTypeList = _composerTypes .Where(x => { - // use the min level specified by the attribute if any - // otherwise, user composers have Run min level, anything else is Unknown (always run) + // use the min/max levels specified by the attribute if any + // otherwise, min: user composers are Run, anything else is Unknown (always run) + // max: everything is Run (always run) var attr = x.GetCustomAttribute(); var minLevel = attr?.MinLevel ?? (x.Implements() ? RuntimeLevel.Run : RuntimeLevel.Unknown); - return _composition.RuntimeState.Level >= minLevel; + var maxLevel = attr?.MaxLevel ?? RuntimeLevel.Run; + return _composition.RuntimeState.Level >= minLevel && _composition.RuntimeState.Level <= maxLevel; }) .ToList(); From f6fdc9ae2d33b38d41d4c6a6626d11a6b5f83849 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 15 Jan 2019 23:46:58 +1100 Subject: [PATCH 100/223] Updates test, fixes some other issues during testing --- .../Models/Packaging/PreInstallWarnings.cs | 2 ++ .../Packaging/ConflictingPackageData.cs | 2 +- .../Packaging/PackageInstallationTest.cs | 13 +++++++++++-- .../views/packages/views/installed.controller.js | 2 +- src/Umbraco.Web/Search/ExamineComponent.cs | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs b/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs index 18b63ced88..f0acb2a46b 100644 --- a/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs +++ b/src/Umbraco.Core/Models/Packaging/PreInstallWarnings.cs @@ -9,6 +9,8 @@ namespace Umbraco.Core.Models.Packaging { public IEnumerable UnsecureFiles { get; set; } = Enumerable.Empty(); public IEnumerable FilesReplaced { get; set; } = Enumerable.Empty(); + + //TODO: Shouldn't we detect other conflicting entities too ? public IEnumerable ConflictingMacros { get; set; } = Enumerable.Empty(); public IEnumerable ConflictingTemplates { get; set; } = Enumerable.Empty(); public IEnumerable ConflictingStylesheets { get; set; } = Enumerable.Empty(); diff --git a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs index a37195806e..82693677fb 100644 --- a/src/Umbraco.Core/Packaging/ConflictingPackageData.cs +++ b/src/Umbraco.Core/Packaging/ConflictingPackageData.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Packaging return stylesheetNodes .Select(n => { - var xElement = n.Element("Name"); + var xElement = n.Element("Name") ?? n.Element("name"); ; if (xElement == null) throw new FormatException("Missing \"Name\" element"); diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 62feb64c10..8fcacbeff7 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -6,11 +6,13 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Composing; using Umbraco.Core.IO; +using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; +using File = System.IO.File; namespace Umbraco.Tests.Packaging { @@ -79,7 +81,11 @@ namespace Umbraco.Tests.Packaging [Test] public void Can_Read_Compiled_Package_Warnings() { - + //copy a file to the same path that the package will install so we can detect file conflicts + var path = IOHelper.MapPath("~/" + _testBaseFolder); + var filePath = Path.Combine(path, "bin", "Auros.DocumentTypePicker.dll"); + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + File.WriteAllText(filePath, "test"); var preInstallWarnings = PackageInstallation.ReadPackage( //this is where our test zip file is @@ -87,7 +93,10 @@ namespace Umbraco.Tests.Packaging .Warnings; Assert.IsNotNull(preInstallWarnings); - //TODO: Assert! + Assert.AreEqual(preInstallWarnings.FilesReplaced.Count(), 1); + Assert.AreEqual(preInstallWarnings.FilesReplaced.First(), "bin\\Auros.DocumentTypePicker.dll"); + + //TODO: More Asserts } [Test] diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js index 6e0e162e86..5265897708 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js @@ -25,7 +25,7 @@ var labelKeys = [ "packager_installStateUninstalling", - "packager_installStateComplete", + "packager_installStateComplete" ]; localizationService.localizeMany(labelKeys).then(function (values) { diff --git a/src/Umbraco.Web/Search/ExamineComponent.cs b/src/Umbraco.Web/Search/ExamineComponent.cs index 09d0c555da..336fcc7aec 100644 --- a/src/Umbraco.Web/Search/ExamineComponent.cs +++ b/src/Umbraco.Web/Search/ExamineComponent.cs @@ -446,7 +446,7 @@ namespace Umbraco.Web.Search while (page * pageSize < total) { //paging with examine, see https://shazwazza.com/post/paging-with-examine/ - var results = searcher.CreateQuery().Field("nodeType", id).Execute(maxResults: pageSize * (page + 1)); + var results = searcher.CreateQuery().Field("nodeType", id.ToInvariantString()).Execute(maxResults: pageSize * (page + 1)); total = results.TotalItemCount; var paged = results.Skip(page * pageSize); From 709df804e5ac3069e768eba7b153fc82f3889890 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 00:13:40 +1100 Subject: [PATCH 101/223] Updates tests and better type support for importing content --- .../Models/Packaging/CompiledPackage.cs | 12 +- .../Packaging/CompiledPackageDocument.cs | 26 +++++ .../Models/Packaging/CompiledPackageFile.cs | 25 +++++ .../Packaging/CompiledPackageXmlParser.cs | 10 +- .../Packaging/PackageDataInstallation.cs | 59 +++++----- .../Packaging/PackageInstallation.cs | 1 - src/Umbraco.Core/Umbraco.Core.csproj | 2 + .../PackageDataInstallationTests.cs} | 105 +++++++++--------- .../Packaging/PackageInstallationTest.cs | 39 ++++++- .../Packaging/Packages/Hello_1.0.0.zip | Bin 0 -> 1529 bytes src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- 11 files changed, 172 insertions(+), 109 deletions(-) create mode 100644 src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs create mode 100644 src/Umbraco.Core/Models/Packaging/CompiledPackageFile.cs rename src/Umbraco.Tests/{Services/Importing/PackageImportTests.cs => Packaging/PackageDataInstallationTests.cs} (84%) create mode 100644 src/Umbraco.Tests/Packaging/Packages/Hello_1.0.0.zip diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index d458337bf9..a852fcc997 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -39,16 +39,6 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable Languages { get; set; } //fixme: make strongly typed public IEnumerable DictionaryItems { get; set; } //fixme: make strongly typed public IEnumerable DocumentTypes { get; set; } //fixme: make strongly typed - public IEnumerable Documents { get; set; } //fixme: make strongly typed + public IEnumerable Documents { get; set; } } - - public class CompiledPackageFile - { - public string OriginalPath { get; set; } - public string UniqueFileName { get; set; } - public string OriginalName { get; set; } - - } - - } diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs new file mode 100644 index 0000000000..c41966dfe1 --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs @@ -0,0 +1,26 @@ +using System; +using System.Xml.Linq; + +namespace Umbraco.Core.Models.Packaging +{ + public class CompiledPackageDocument + { + public static CompiledPackageDocument Create(XElement xml) + { + if (xml.Name.LocalName != "DocumentSet") + throw new ArgumentException("The xml isn't formatted correctly, a document element is defined by ", nameof(xml)); + return new CompiledPackageDocument + { + XmlData = xml, + ImportMode = xml.AttributeValue("importMode") + }; + } + + public string ImportMode { get; set; } //this is never used + + /// + /// The serialized version of the content + /// + public XElement XmlData { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackageFile.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackageFile.cs new file mode 100644 index 0000000000..2cb989b42b --- /dev/null +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackageFile.cs @@ -0,0 +1,25 @@ +using System; +using System.Xml.Linq; + +namespace Umbraco.Core.Models.Packaging +{ + public class CompiledPackageFile + { + public static CompiledPackageFile Create(XElement xml) + { + if (xml.Name.LocalName != "file") + throw new ArgumentException("The xml isn't formatted correctly, a file element is defined by ", nameof(xml)); + return new CompiledPackageFile + { + UniqueFileName = xml.Element("guid")?.Value, + OriginalName = xml.Element("orgName")?.Value, + OriginalPath = xml.Element("orgPath")?.Value + }; + } + + public string OriginalPath { get; set; } + public string UniqueFileName { get; set; } + public string OriginalName { get; set; } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index be9c69667a..4695ccb673 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -53,13 +53,7 @@ namespace Umbraco.Core.Packaging UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type")), Control = package.Element("control")?.Value, Actions = xml.Root.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value - Files = xml.Root.Element("files")?.Elements("file")?.Select(x => new CompiledPackageFile - { - UniqueFileName = x.Element("guid")?.Value, - OriginalName = x.Element("orgName")?.Value, - OriginalPath = x.Element("orgPath")?.Value - }).ToList() ?? new List(), - + Files = xml.Root.Element("files")?.Elements("file")?.Select(CompiledPackageFile.Create).ToList() ?? new List(), Macros = xml.Root.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), Templates = xml.Root.Element("Templates")?.Elements("Template") ?? Enumerable.Empty(), Stylesheets = xml.Root.Element("Stylesheets")?.Elements("styleSheet") ?? Enumerable.Empty(), @@ -67,7 +61,7 @@ namespace Umbraco.Core.Packaging Languages = xml.Root.Element("Languages")?.Elements("Language") ?? Enumerable.Empty(), DictionaryItems = xml.Root.Element("DictionaryItems")?.Elements("DictionaryItem") ?? Enumerable.Empty(), DocumentTypes = xml.Root.Element("DocumentTypes")?.Elements("DocumentType") ?? Enumerable.Empty(), - Documents = xml.Root.Element("Documents")?.Elements("DocumentSet") ?? Enumerable.Empty(), + Documents = xml.Root.Element("Documents")?.Elements("DocumentSet")?.Select(CompiledPackageDocument.Create) ?? Enumerable.Empty(), }; def.Warnings = GetPreInstallWarnings(def, applicationRootFolder); diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 1743bb0041..2212a8957d 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -170,51 +170,48 @@ namespace Umbraco.Core.Packaging #region Content - public IEnumerable ImportContent(IEnumerable element, IDictionary importedDocumentTypes, int userId) + public IEnumerable ImportContent(IEnumerable docs, IDictionary importedDocumentTypes, int userId) { - return element.Elements("DocumentSet").SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId)); + return docs.SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId)); } /// /// Imports and saves package xml as /// - /// Xml to import + /// Xml to import /// Optional parent Id for the content being imported /// A dictionary of already imported document types (basically used as a cache) /// Optional Id of the user performing the import /// An enumrable list of generated content - public IEnumerable ImportContent(XElement element, int parentId, IDictionary importedDocumentTypes, int userId) + public IEnumerable ImportContent(CompiledPackageDocument packageDocument, int parentId, IDictionary importedDocumentTypes, int userId) { - var name = element.Name.LocalName; - if (name.Equals("DocumentSet")) - { - //This is a regular deep-structured import - var roots = from doc in element.Elements() - where (string)doc.Attribute("isDoc") == "" - select doc; + var element = packageDocument.XmlData; - var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList(); - if (contents.Any()) - _contentService.Save(contents, userId); - - return contents; - } + var roots = from doc in element.Elements() + where (string)doc.Attribute("isDoc") == "" + select doc; - var attribute = element.Attribute("isDoc"); - if (attribute != null) - { - //This is a single doc import - var elements = new List { element }; - var contents = ParseDocumentRootXml(elements, parentId, importedDocumentTypes).ToList(); - if (contents.Any()) - _contentService.Save(contents, userId); - - return contents; - } + var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList(); + if (contents.Any()) + _contentService.Save(contents, userId); - throw new ArgumentException( - "The passed in XElement is not valid! It does not contain a root element called " + - "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); + return contents; + + //var attribute = element.Attribute("isDoc"); + //if (attribute != null) + //{ + // //This is a single doc import + // var elements = new List { element }; + // var contents = ParseDocumentRootXml(elements, parentId, importedDocumentTypes).ToList(); + // if (contents.Any()) + // _contentService.Save(contents, userId); + + // return contents; + //} + + //throw new ArgumentException( + // "The passed in XElement is not valid! It does not contain a root element called " + + // "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); } private IEnumerable ParseDocumentRootXml(IEnumerable roots, int parentId, IDictionary importedContentTypes) diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index ae9b8173f5..d7bb72836e 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -111,7 +111,6 @@ namespace Umbraco.Core.Packaging installationSummary.ContentInstalled = _packageDataInstallation.ImportContent(compiledPackage.Documents, importedDocTypes, userId); installationSummary.Actions = _parser.GetPackageActions(XElement.Parse(compiledPackage.Actions), compiledPackage.Name); installationSummary.MetaData = compiledPackage; - //fixme: Verify that this will work! installationSummary.FilesInstalled = packageDefinition.Files; //make sure the definition is up to date with everything diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 6b334b234b..cd974613eb 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -432,6 +432,8 @@ + + diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs similarity index 84% rename from src/Umbraco.Tests/Services/Importing/PackageImportTests.cs rename to src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs index f29a43c504..aecef34f4f 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs @@ -3,24 +3,27 @@ using System.Linq; using System.Threading; using System.Xml.Linq; using NUnit.Framework; -using Umbraco.Core.Models; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Composing.Composers; using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Tests.Services; +using Umbraco.Tests.Services.Importing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services.Importing +namespace Umbraco.Tests.Packaging { [TestFixture] [Category("Slow")] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PackageImportTests : TestWithSomeContentBase + public class PackageDataInstallationTests : TestWithSomeContentBase { [HideFromTypeFinder] public class Editor1 : DataEditor @@ -66,7 +69,7 @@ namespace Umbraco.Tests.Services.Importing Composition.ComposeFileSystems(); } - private PackageDataInstallation PackagingService => Factory.GetInstance(); + private PackageDataInstallation PackageDataInstallation => Factory.GetInstance(); [Test] public void PackagingService_Can_Import_uBlogsy_ContentTypes_And_Verify_Structure() @@ -79,9 +82,9 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypes = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var dataTypes = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); @@ -126,9 +129,9 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypes = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var dataTypes = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); // Assert var mRBasePage = contentTypes.First(x => x.Alias == "MRBasePage"); @@ -151,9 +154,9 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypes = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var dataTypes = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); @@ -190,7 +193,7 @@ namespace Umbraco.Tests.Services.Importing var init = ServiceContext.FileService.GetTemplates().Count(); // Act - var templates = PackagingService.ImportTemplates(element.Elements("Template").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(element.Elements("Template").ToList(), 0); var numberOfTemplates = (from doc in element.Elements("Template") select doc).Count(); var allTemplates = ServiceContext.FileService.GetTemplates(); @@ -213,7 +216,7 @@ namespace Umbraco.Tests.Services.Importing // Act - var templates = PackagingService.ImportTemplate(element.Elements("Template").First(), 0); + var templates = PackageDataInstallation.ImportTemplate(element.Elements("Template").First(), 0); // Assert Assert.That(templates, Is.Not.Null); @@ -233,9 +236,9 @@ namespace Umbraco.Tests.Services.Importing // Act - var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); // Assert @@ -268,13 +271,13 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); //Assert - Re-Import contenttypes doesn't throw - Assert.DoesNotThrow(() => PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0)); + Assert.DoesNotThrow(() => PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0)); Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); Assert.That(dataTypeDefinitions, Is.Not.Null); Assert.That(dataTypeDefinitions.Any(), Is.True); @@ -292,13 +295,13 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = xml.Descendants("DocumentTypes").First(); // Act - var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); //Assert - Re-Import contenttypes doesn't throw - Assert.DoesNotThrow(() => PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0)); + Assert.DoesNotThrow(() => PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0)); Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); Assert.That(dataTypeDefinitions, Is.Not.Null); Assert.That(dataTypeDefinitions.Any(), Is.True); @@ -314,13 +317,13 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var docTypesElement = xml.Descendants("DocumentTypes").First(); var element = xml.Descendants("DocumentSet").First(); - + var packageDocument = CompiledPackageDocument.Create(element); // Act - var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); + var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); - var contents = PackagingService.ImportContent(element, -1, importedContentTypes, 0); + var contents = PackageDataInstallation.ImportContent(packageDocument, -1, importedContentTypes, 0); var numberOfDocs = (from doc in element.Descendants() where (string) doc.Attribute("isDoc") == "" select doc).Count(); @@ -348,13 +351,13 @@ namespace Umbraco.Tests.Services.Importing var dataTypeElement = xml.Descendants("DataTypes").First(); var docTypesElement = xml.Descendants("DocumentTypes").First(); var element = xml.Descendants("DocumentSet").First(); - + var packageDocument = CompiledPackageDocument.Create(element); // Act - var dataTypeDefinitions = PackagingService.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); + var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); - var contents = PackagingService.ImportContent(element, -1, importedContentTypes, 0); + var contents = PackageDataInstallation.ImportContent(packageDocument, -1, importedContentTypes, 0); var numberOfDocs = (from doc in element.Descendants() where (string)doc.Attribute("isDoc") == "" select doc).Count(); @@ -387,7 +390,7 @@ namespace Umbraco.Tests.Services.Importing // Act - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); // Assert @@ -404,7 +407,7 @@ namespace Umbraco.Tests.Services.Importing // Act - var contentTypes = PackagingService.ImportDocumentType(docTypeElement, 0); + var contentTypes = PackageDataInstallation.ImportDocumentType(docTypeElement, 0); // Assert Assert.That(contentTypes.Any(), Is.True); @@ -422,7 +425,7 @@ namespace Umbraco.Tests.Services.Importing var serializer = Factory.GetInstance(); // Act - var contentTypes = PackagingService.ImportDocumentType(docTypeElement, 0); + var contentTypes = PackageDataInstallation.ImportDocumentType(docTypeElement, 0); var contentType = contentTypes.FirstOrDefault(); var element = serializer.Serialize(contentType); @@ -444,8 +447,8 @@ namespace Umbraco.Tests.Services.Importing var docTypeElement = XElement.Parse(strXml); // Act - var contentTypes = PackagingService.ImportDocumentType(docTypeElement, 0); - var contentTypesUpdated = PackagingService.ImportDocumentType(docTypeElement, 0); + var contentTypes = PackageDataInstallation.ImportDocumentType(docTypeElement, 0); + var contentTypesUpdated = PackageDataInstallation.ImportDocumentType(docTypeElement, 0); // Assert Assert.That(contentTypes.Any(), Is.True); @@ -475,8 +478,8 @@ namespace Umbraco.Tests.Services.Importing // Act var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var templatesAfterUpdate = PackagingService.ImportTemplates(templateElementUpdated.Elements("Template").ToList(), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var templatesAfterUpdate = PackageDataInstallation.ImportTemplates(templateElementUpdated.Elements("Template").ToList(), 0); var allTemplates = fileService.GetTemplates(); // Assert @@ -502,7 +505,7 @@ namespace Umbraco.Tests.Services.Importing AddLanguages(); // Act - PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); + PackageDataInstallation.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert AssertDictionaryItem("Parent", expectedEnglishParentValue, "en-GB"); @@ -524,7 +527,7 @@ namespace Umbraco.Tests.Services.Importing AddLanguages(); // Act - var dictionaryItems = PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); + var dictionaryItems = PackageDataInstallation.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(parentKey), "DictionaryItem parentKey does not exist"); @@ -553,7 +556,7 @@ namespace Umbraco.Tests.Services.Importing AddExistingEnglishAndNorwegianParentDictionaryItem(expectedEnglishParentValue, expectedNorwegianParentValue); // Act - PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); + PackageDataInstallation.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert AssertDictionaryItem("Parent", expectedEnglishParentValue, "en-GB"); @@ -578,7 +581,7 @@ namespace Umbraco.Tests.Services.Importing AddExistingEnglishParentDictionaryItem(expectedEnglishParentValue); // Act - PackagingService.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); + PackageDataInstallation.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert AssertDictionaryItem("Parent", expectedEnglishParentValue, "en-GB"); @@ -595,7 +598,7 @@ namespace Umbraco.Tests.Services.Importing var LanguageItemsElement = newPackageXml.Elements("Languages").First(); // Act - var languages = PackagingService.ImportLanguages(LanguageItemsElement.Elements("Language"), 0); + var languages = PackageDataInstallation.ImportLanguages(LanguageItemsElement.Elements("Language"), 0); var allLanguages = ServiceContext.LocalizationService.GetAllLanguages(); // Assert @@ -616,7 +619,7 @@ namespace Umbraco.Tests.Services.Importing // Act - var macros = PackagingService.ImportMacros(macrosElement.Elements("macro"), 0).ToList(); + var macros = PackageDataInstallation.ImportMacros(macrosElement.Elements("macro"), 0).ToList(); // Assert Assert.That(macros.Any(), Is.True); @@ -638,7 +641,7 @@ namespace Umbraco.Tests.Services.Importing // Act - var macros = PackagingService.ImportMacros(macrosElement.Elements("macro"), 0).ToList(); + var macros = PackageDataInstallation.ImportMacros(macrosElement.Elements("macro"), 0).ToList(); // Assert Assert.That(macros.Any(), Is.True); @@ -662,8 +665,8 @@ namespace Umbraco.Tests.Services.Importing // Act - var templates = PackagingService.ImportTemplates(templateElement.Elements("Template").ToList(), 0); - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var templates = PackageDataInstallation.ImportTemplates(templateElement.Elements("Template").ToList(), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); // Assert @@ -690,7 +693,7 @@ namespace Umbraco.Tests.Services.Importing // Act - var contentTypes = PackagingService.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); + var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypeElement.Elements("DocumentType"), 0); var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); // Assert diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 8fcacbeff7..d944b638ad 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -53,14 +53,15 @@ namespace Umbraco.Tests.Packaging applicationRootFolder: new DirectoryInfo(IOHelper.GetRootDirectorySafe()), packageExtractionFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder - private const string DocumentTypePickerUmb = "Document_Type_Picker_1.1.umb"; + private const string DocumentTypePickerPackage = "Document_Type_Picker_1.1.umb"; + private const string HelloPackage = "Hello_1.0.0.zip"; [Test] - public void Can_Read_Compiled_Package() + public void Can_Read_Compiled_Package_1() { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); Assert.IsNotNull(package); Assert.AreEqual(1, package.Files.Count); Assert.AreEqual("095e064b-ba4d-442d-9006-3050983c13d8.dll", package.Files[0].UniqueFileName); @@ -78,6 +79,32 @@ namespace Umbraco.Tests.Packaging Assert.AreEqual(1, package.DataTypes.Count()); } + [Test] + public void Can_Read_Compiled_Package_2() + { + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), HelloPackage))); + Assert.IsNotNull(package); + Assert.AreEqual(0, package.Files.Count); + Assert.AreEqual("Hello", package.Name); + Assert.AreEqual("1.0.0", package.Version); + Assert.AreEqual("http://opensource.org/licenses/MIT", package.LicenseUrl); + Assert.AreEqual("MIT License", package.License); + Assert.AreEqual(8, package.UmbracoVersion.Major); + Assert.AreEqual(0, package.UmbracoVersion.Minor); + Assert.AreEqual(0, package.UmbracoVersion.Build); + Assert.AreEqual(RequirementsType.Strict, package.UmbracoVersionRequirementsType); + Assert.AreEqual("asdf", package.Author); + Assert.AreEqual("http://hello.com", package.AuthorUrl); + Assert.AreEqual("asdf", package.Readme); + Assert.AreEqual(1, package.Documents.Count()); + Assert.AreEqual("root", package.Documents.First().ImportMode); + Assert.AreEqual(1, package.DocumentTypes.Count()); + Assert.AreEqual(1, package.Templates.Count()); + Assert.AreEqual(1, package.DataTypes.Count()); + } + [Test] public void Can_Read_Compiled_Package_Warnings() { @@ -89,7 +116,7 @@ namespace Umbraco.Tests.Packaging var preInstallWarnings = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))) + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))) .Warnings; Assert.IsNotNull(preInstallWarnings); @@ -104,7 +131,7 @@ namespace Umbraco.Tests.Packaging { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; @@ -126,7 +153,7 @@ namespace Umbraco.Tests.Packaging { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); diff --git a/src/Umbraco.Tests/Packaging/Packages/Hello_1.0.0.zip b/src/Umbraco.Tests/Packaging/Packages/Hello_1.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..c95cb282d14065396851362194fd37007cb632fe GIT binary patch literal 1529 zcmVeh01E&B0B~VrYhh<)E_iKh%~wlv z+cpqBH#7MUEDt@I;=|N46cg8)q?)l(kENssPYxgnN@yrT0YTfEOnzAp{Ym``U63FN z=#iw8OAofN59}_!UF?GY{PlP6@@bnH5118%=2O${Ii`X0m?k7&PtB62*2sJrK7SUJ z+vpa>AJG~EWf(z9GF%vTO^`gL)e6=-MXO@uXp6(&aF)@)uGXzYx(&f=&k5{?Y~>`T z`8$?{f!(ZHQAT2%7uYCSHZ?b#?`A^bCLYEICII&)wq zlvXw((q2rrfnBN|8U9ofhPOE9g~9hbJT;e`k(isU4rp!BpOl58z^)gngyg`0W7Z2r zvO_%H2uZzYJ=&_v23}joH$WxdDCTOkQIVvFU_auhARM1KW+Q1lXeQy@C;>ac&-d4} ztJT%Lu>IjfD59$bRRP#-1q3r1ms-RPV~M#zwmZuBf+m0-qg25z*zT7g&G0Q8&L9cY zqT>yH)A)$@Q!_#s`QtvahJNf={%GJ>k)L9#?Tqzq16hPKamlH#I%S9a*ktxuccmOqfY~kVhf~U@|r9ovW&p2A(tS=&OvN0=6rVw5O;oFE=R9X>J;i z3{rQR*_@YSFj9pNUPi+GZ5d^x*kC}Jvl43+%n8qwbXP~J@?8rQ&4jMk1Q(s|5|ssn zT4^^z^#+{Ea9?J)kE4Ek>3G&)FdmBxCl*RBJ!?2{5D)S0+_HOY4r8kLe{R?~WtFXY+&PpM8(R%p3C&USUSli5C%?>96{ zaBkdT&M;{7dmn5;0U?acns6g_u{b?rQ^sNIN0qwk?)OB4QaDMcZj0! zx-Mk!1B51BHqBJLQaVD@S)e=-O>5s&TgTA!-lL2FUqlet3ZWLvd1Su>^ch_j=P{S< z>D#E!z{89_=DpV$ej<@b)K~F$BiHZa(WNzV(gg4yMHU+MVU#(kI~=B|8@ut3D8P9V!qgnX#Y}X;HL6-zceaM{-|9=pq@ubP@zHhGS#oR~cAwz5 zt$brV$O<|?8bs43>%1F~uSmWDOyPr}sj5G4)LT5nJxPmRTv?L%h?j9z^t7?~sx07R z%+NH9sb;Yq^0o8@Z2J8C*-tlUPfHHEd6{Lv{89~Q8DxW=217?m)Rue?-+3F1dHb=q zKry2&HG?l8$R}d^IXpgE_6-cc65{Xl5J&pNmJFkQ(1=@W8gqE2oV|di(cK<+0Di}P zgB{={LWO*Ky?sC|-XM6b0h%dUmkia$KL7Hmr2NGKrVRn)Yic6i#uxRvI-F$ROKp-! zhAWjGP*yg3>mT_du8A)fhZ`@?ZajQiowMMbwQz$Xx#`0fv&n+3ry;nCyRi@7yWKbb zzfem70u%rg000080Jn)RPO_5QS%C!r02>eh01E&B0000000000000000001RVPk7y fXJsyUZER3W1qJ{B000310RTAw0062500000ehA61 literal 0 HcmV?d00001 diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 8d3900088c..e49ba250fa 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -444,7 +444,7 @@ - + True True From db2a003444664d12935fed139d94ff0dc2cb76af Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 00:54:25 +1100 Subject: [PATCH 102/223] change how the install status works, fixes infinite loop --- .../src/views/packages/views/install-local.controller.js | 2 +- src/Umbraco.Web/Search/ExamineComponent.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js index 6753fad942..17b417de48 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js @@ -171,7 +171,7 @@ }, installError) .then(function (pack) { - vm.installState.status = labels.installStateRestarting; + vm.installState.status = labels.installStateInstalling; vm.installState.progress = "75"; return packageResource.installData(pack); }, diff --git a/src/Umbraco.Web/Search/ExamineComponent.cs b/src/Umbraco.Web/Search/ExamineComponent.cs index 336fcc7aec..05a1258441 100644 --- a/src/Umbraco.Web/Search/ExamineComponent.cs +++ b/src/Umbraco.Web/Search/ExamineComponent.cs @@ -453,6 +453,7 @@ namespace Umbraco.Web.Search foreach (var item in paged) if (int.TryParse(item.Id, out var contentId)) DeleteIndexForEntity(contentId, false); + page++; } } } From 16eae7c4fc894d31b4510f6953ad9f545101d713 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 14:54:34 +0100 Subject: [PATCH 103/223] #3305 Added optional culture parameter to Children and Descendants extension methods --- .../PublishedContentDataTableTests.cs | 496 ++--- .../PublishedContent/PublishedContentTests.cs | 1756 ++++++++--------- .../PublishedContent/PublishedMediaTests.cs | 1016 +++++----- src/Umbraco.Web/PublishedContentExtensions.cs | 115 +- 4 files changed, 1700 insertions(+), 1683 deletions(-) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index 3af930c4c3..4e3c17403b 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -1,248 +1,248 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; - -namespace Umbraco.Tests.PublishedContent -{ - /// - /// Unit tests for IPublishedContent and extensions - /// - [TestFixture] - public class PublishedContentDataTableTests : BaseWebTest - { - public override void SetUp() - { - base.SetUp(); - - // need to specify a different callback for testing - PublishedContentExtensions.GetPropertyAliasesAndNames = (services, alias) => - { - var userFields = new Dictionary() - { - {"property1", "Property 1"}, - {"property2", "Property 2"} - }; - if (alias == "Child") - { - userFields.Add("property4", "Property 4"); - } - else - { - userFields.Add("property3", "Property 3"); - } - - //ensure the standard fields are there - var allFields = new Dictionary() - { - {"Id", "Id"}, - {"NodeName", "NodeName"}, - {"NodeTypeAlias", "NodeTypeAlias"}, - {"CreateDate", "CreateDate"}, - {"UpdateDate", "UpdateDate"}, - {"CreatorName", "CreatorName"}, - {"WriterName", "WriterName"}, - {"Url", "Url"} - }; - foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key))) - { - allFields.Add(f.Key, f.Value); - } - return allFields; - }; - var umbracoContext = GetUmbracoContext("/test"); - - //set the UmbracoContext.Current since the extension methods rely on it - Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; - } - - public override void TearDown() - { - base.TearDown(); - Umbraco.Web.PublishedContentExtensions.GetPropertyAliasesAndNames = null; - } - - [Test] - public void To_DataTable() - { - var doc = GetContent(true, 1); - var dt = doc.ChildrenAsTable(Current.Services); - - Assert.AreEqual(11, dt.Columns.Count); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); - Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); - Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); - Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); - Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); - Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); - Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); - Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); - Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); - } - - [Test] - public void To_DataTable_With_Filter() - { - var doc = GetContent(true, 1); - //change a doc type alias - var c = (TestPublishedContent) doc.Children.ElementAt(0); - c.ContentType = new PublishedContentType(22, "DontMatch", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); - - var dt = doc.ChildrenAsTable(Current.Services, "Child"); - - Assert.AreEqual(11, dt.Columns.Count); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); - Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); - Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); - Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); - Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); - Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); - } - - [Test] - public void To_DataTable_No_Rows() - { - var doc = GetContent(false, 1); - var dt = doc.ChildrenAsTable(Current.Services); - //will return an empty data table - Assert.AreEqual(0, dt.Columns.Count); - Assert.AreEqual(0, dt.Rows.Count); - } - - private IPublishedContent GetContent(bool createChildren, int indexVals) - { - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of())) { Id = 1 }); - - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); - var contentTypeAlias = createChildren ? "Parent" : "Child"; - var d = new TestPublishedContent - { - CreateDate = DateTime.Now, - CreatorId = 1, - CreatorName = "Shannon", - Id = 3, - SortOrder = 4, - TemplateId = 5, - UpdateDate = DateTime.Now, - Path = "-1,3", - UrlSegment = "home-page", - Name = "Page" + Guid.NewGuid().ToString(), - Version = Guid.NewGuid(), - WriterId = 1, - WriterName = "Shannon", - Parent = null, - Level = 1, - Children = new List() - }; - d.Properties = new Collection(new List - { - new RawValueProperty(factory.CreatePropertyType("property1", 1), d, "value" + indexVals), - new RawValueProperty(factory.CreatePropertyType("property2", 1), d, "value" + (indexVals + 1)) - }); - if (createChildren) - { - d.Children = new List() - { - GetContent(false, indexVals + 3), - GetContent(false, indexVals + 6), - GetContent(false, indexVals + 9) - }; - } - - if (!createChildren) - { - //create additional columns, used to test the different columns for child nodes - ((Collection) d.Properties).Add( - new RawValueProperty(factory.CreatePropertyType("property4",1), d, "value" + (indexVals + 2))); - } - else - { - ((Collection) d.Properties).Add( - new RawValueProperty(factory.CreatePropertyType("property3", 1), d, "value" + (indexVals + 2))); - } - - d.ContentType = new PublishedContentType(22, contentTypeAlias, PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); - return d; - } - - // note - could probably rewrite those tests using SolidPublishedContentCache - // l8tr... - private class TestPublishedContent : IPublishedContent - { - public string Url { get; set; } - public string GetUrl(string culture = null) => throw new NotSupportedException(); - - public PublishedItemType ItemType { get; set; } - - IPublishedContent IPublishedContent.Parent - { - get { return Parent; } - } - - IEnumerable IPublishedContent.Children - { - get { return Children; } - } - - public IPublishedContent Parent { get; set; } - public int Id { get; set; } - public Guid Key { get; set; } - public int? TemplateId { get; set; } - public int SortOrder { get; set; } - public string Name { get; set; } - public PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException(); - public IReadOnlyDictionary Cultures => throw new NotSupportedException(); - public string UrlSegment { get; set; } - public string WriterName { get; set; } - public string CreatorName { get; set; } - public int WriterId { get; set; } - public int CreatorId { get; set; } - public string Path { get; set; } - public DateTime CreateDate { get; set; } - public DateTime UpdateDate { get; set; } - public Guid Version { get; set; } - public int Level { get; set; } - public bool IsDraft(string culture = null) => false; - - public IEnumerable Properties { get; set; } - - public IEnumerable Children { get; set; } - - public IPublishedProperty GetProperty(string alias) - { - return Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - } - - public IPublishedProperty GetProperty(string alias, bool recurse) - { - var property = GetProperty(alias); - if (recurse == false) return property; - - IPublishedContent content = this; - while (content != null && (property == null || property.HasValue() == false)) - { - content = content.Parent; - property = content == null ? null : content.GetProperty(alias); - } - - return property; - } - - public PublishedContentType ContentType { get; set; } - } - } -} +//using System; +//using System.Collections.Generic; +//using System.Collections.ObjectModel; +//using System.Linq; +//using Moq; +//using NUnit.Framework; +//using Umbraco.Core; +//using Umbraco.Core.Composing; +//using Umbraco.Core.Logging; +//using Umbraco.Core.Models; +//using Umbraco.Core.Models.PublishedContent; +//using Umbraco.Core.PropertyEditors; +//using Umbraco.Core.Services; +//using Umbraco.Tests.TestHelpers; +//using Umbraco.Web; +// +//namespace Umbraco.Tests.PublishedContent +//{ +// /// +// /// Unit tests for IPublishedContent and extensions +// /// +// [TestFixture] +// public class PublishedContentDataTableTests : BaseWebTest +// { +// public override void SetUp() +// { +// base.SetUp(); +// +// // need to specify a different callback for testing +// PublishedContentExtensions.GetPropertyAliasesAndNames = (services, alias) => +// { +// var userFields = new Dictionary() +// { +// {"property1", "Property 1"}, +// {"property2", "Property 2"} +// }; +// if (alias == "Child") +// { +// userFields.Add("property4", "Property 4"); +// } +// else +// { +// userFields.Add("property3", "Property 3"); +// } +// +// //ensure the standard fields are there +// var allFields = new Dictionary() +// { +// {"Id", "Id"}, +// {"NodeName", "NodeName"}, +// {"NodeTypeAlias", "NodeTypeAlias"}, +// {"CreateDate", "CreateDate"}, +// {"UpdateDate", "UpdateDate"}, +// {"CreatorName", "CreatorName"}, +// {"WriterName", "WriterName"}, +// {"Url", "Url"} +// }; +// foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key))) +// { +// allFields.Add(f.Key, f.Value); +// } +// return allFields; +// }; +// var umbracoContext = GetUmbracoContext("/test"); +// +// //set the UmbracoContext.Current since the extension methods rely on it +// Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; +// } +// +// public override void TearDown() +// { +// base.TearDown(); +// Umbraco.Web.PublishedContentExtensions.GetPropertyAliasesAndNames = null; +// } +// +// [Test] +// public void To_DataTable() +// { +// var doc = GetContent(true, 1); +// var dt = doc.ChildrenAsTable(Current.Services); +// +// Assert.AreEqual(11, dt.Columns.Count); +// Assert.AreEqual(3, dt.Rows.Count); +// Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); +// Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); +// Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); +// Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); +// Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); +// Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); +// Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); +// Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); +// Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); +// } +// +// [Test] +// public void To_DataTable_With_Filter() +// { +// var doc = GetContent(true, 1); +// //change a doc type alias +// var c = (TestPublishedContent) doc.Children.ElementAt(0); +// c.ContentType = new PublishedContentType(22, "DontMatch", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); +// +// var dt = doc.ChildrenAsTable(Current.Services, "Child"); +// +// Assert.AreEqual(11, dt.Columns.Count); +// Assert.AreEqual(2, dt.Rows.Count); +// Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); +// Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); +// Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); +// Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); +// Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); +// Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); +// } +// +// [Test] +// public void To_DataTable_No_Rows() +// { +// var doc = GetContent(false, 1); +// var dt = doc.ChildrenAsTable(Current.Services); +// //will return an empty data table +// Assert.AreEqual(0, dt.Columns.Count); +// Assert.AreEqual(0, dt.Rows.Count); +// } +// +// private IPublishedContent GetContent(bool createChildren, int indexVals) +// { +// var dataTypeService = new TestObjects.TestDataTypeService( +// new DataType(new VoidEditor(Mock.Of())) { Id = 1 }); +// +// var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); +// var contentTypeAlias = createChildren ? "Parent" : "Child"; +// var d = new TestPublishedContent +// { +// CreateDate = DateTime.Now, +// CreatorId = 1, +// CreatorName = "Shannon", +// Id = 3, +// SortOrder = 4, +// TemplateId = 5, +// UpdateDate = DateTime.Now, +// Path = "-1,3", +// UrlSegment = "home-page", +// Name = "Page" + Guid.NewGuid().ToString(), +// Version = Guid.NewGuid(), +// WriterId = 1, +// WriterName = "Shannon", +// Parent = null, +// Level = 1, +// Children = new List() +// }; +// d.Properties = new Collection(new List +// { +// new RawValueProperty(factory.CreatePropertyType("property1", 1), d, "value" + indexVals), +// new RawValueProperty(factory.CreatePropertyType("property2", 1), d, "value" + (indexVals + 1)) +// }); +// if (createChildren) +// { +// d.Children = new List() +// { +// GetContent(false, indexVals + 3), +// GetContent(false, indexVals + 6), +// GetContent(false, indexVals + 9) +// }; +// } +// +// if (!createChildren) +// { +// //create additional columns, used to test the different columns for child nodes +// ((Collection) d.Properties).Add( +// new RawValueProperty(factory.CreatePropertyType("property4",1), d, "value" + (indexVals + 2))); +// } +// else +// { +// ((Collection) d.Properties).Add( +// new RawValueProperty(factory.CreatePropertyType("property3", 1), d, "value" + (indexVals + 2))); +// } +// +// d.ContentType = new PublishedContentType(22, contentTypeAlias, PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); +// return d; +// } +// +// // note - could probably rewrite those tests using SolidPublishedContentCache +// // l8tr... +// private class TestPublishedContent : IPublishedContent +// { +// public string Url { get; set; } +// public string GetUrl(string culture = null) => throw new NotSupportedException(); +// +// public PublishedItemType ItemType { get; set; } +// +// IPublishedContent IPublishedContent.Parent +// { +// get { return Parent; } +// } +// +// IEnumerable IPublishedContent.Children +// { +// get { return Children; } +// } +// +// public IPublishedContent Parent { get; set; } +// public int Id { get; set; } +// public Guid Key { get; set; } +// public int? TemplateId { get; set; } +// public int SortOrder { get; set; } +// public string Name { get; set; } +// public PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException(); +// public IReadOnlyDictionary Cultures => throw new NotSupportedException(); +// public string UrlSegment { get; set; } +// public string WriterName { get; set; } +// public string CreatorName { get; set; } +// public int WriterId { get; set; } +// public int CreatorId { get; set; } +// public string Path { get; set; } +// public DateTime CreateDate { get; set; } +// public DateTime UpdateDate { get; set; } +// public Guid Version { get; set; } +// public int Level { get; set; } +// public bool IsDraft(string culture = null) => false; +// +// public IEnumerable Properties { get; set; } +// +// public IEnumerable Children { get; set; } +// +// public IPublishedProperty GetProperty(string alias) +// { +// return Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); +// } +// +// public IPublishedProperty GetProperty(string alias, bool recurse) +// { +// var property = GetProperty(alias); +// if (recurse == false) return property; +// +// IPublishedContent content = this; +// while (content != null && (property == null || property.HasValue() == false)) +// { +// content = content.Parent; +// property = content == null ? null : content.GetProperty(alias); +// } +// +// return property; +// } +// +// public PublishedContentType ContentType { get; set; } +// } +// } +//} diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 914956dce1..6e652fdc68 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -1,878 +1,878 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.PropertyEditors; -using Umbraco.Web; -using Umbraco.Web.PublishedCache; -using Umbraco.Core.Composing; -using Moq; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web.Models.PublishedContent; -using Umbraco.Web.PropertyEditors; - -namespace Umbraco.Tests.PublishedContent -{ - /// - /// Tests the methods on IPublishedContent using the DefaultPublishedContentStore - /// - [TestFixture] - [UmbracoTest(TypeLoader = UmbracoTestOptions.TypeLoader.PerFixture)] - public class PublishedContentTests : PublishedContentTestBase - { - protected override void Compose() - { - base.Compose(); - - Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes())); - Composition.RegisterUnique(); - Composition.RegisterUnique(); - - var logger = Mock.Of(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(logger)) { Id = 1 }, - new DataType(new TrueFalsePropertyEditor(logger)) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(logger)) { Id = 1002 }, - new DataType(new IntegerPropertyEditor(logger)) { Id = 1003 }, - new DataType(new TextboxPropertyEditor(logger)) { Id = 1004 }, - new DataType(new MediaPickerPropertyEditor(logger)) { Id = 1005 }); - Composition.RegisterUnique(f => dataTypeService); - } - - protected override void Initialize() - { - base.Initialize(); - - var factory = Factory.GetInstance() as PublishedContentTypeFactory; - - // need to specify a custom callback for unit tests - // AutoPublishedContentTypes generates properties automatically - // when they are requested, but we must declare those that we - // explicitely want to be here... - - var propertyTypes = new[] - { - // AutoPublishedContentType will auto-generate other properties - factory.CreatePropertyType("umbracoNaviHide", 1001), - factory.CreatePropertyType("selectedNodes", 1), - factory.CreatePropertyType("umbracoUrlAlias", 1), - factory.CreatePropertyType("content", 1002), - factory.CreatePropertyType("testRecursive", 1), - }; - var compositionAliases = new[] { "MyCompositionAlias" }; - var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes); - ContentTypesCache.GetPublishedContentTypeByAlias = alias => type; - } - - protected override TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) - { - var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger); - - // this is so the model factory looks into the test assembly - pluginManager.AssembliesToScan = pluginManager.AssembliesToScan - .Union(new[] { typeof(PublishedContentTests).Assembly }) - .ToList(); - - return pluginManager; - } - - private readonly Guid _node1173Guid = Guid.NewGuid(); - - protected override string GetXmlContent(int templateId) - { - return @" - - - - -]> - - - - - 1 - - - This is some content]]> - - - - - - - - - - - - - - - - 1 - - - - - - - - - -"; - } - - internal IPublishedContent GetNode(int id) - { - var ctx = GetUmbracoContext("/test"); - var doc = ctx.ContentCache.GetById(id); - Assert.IsNotNull(doc); - return doc; - } - - [Test] - public void GetNodeByIds() - { - var ctx = GetUmbracoContext("/test"); - var contentById = ctx.ContentCache.GetById(1173); - Assert.IsNotNull(contentById); - var contentByGuid = ctx.ContentCache.GetById(_node1173Guid); - Assert.IsNotNull(contentByGuid); - Assert.AreEqual(contentById.Id, contentByGuid.Id); - Assert.AreEqual(contentById.Key, contentByGuid.Key); - - contentById = ctx.ContentCache.GetById(666); - Assert.IsNull(contentById); - contentByGuid = ctx.ContentCache.GetById(Guid.NewGuid()); - Assert.IsNull(contentByGuid); - } - - [Test] - public void Is_Last_From_Where_Filter_Dynamic_Linq() - { - var doc = GetNode(1173); - - var items = doc.Children.Where(x => x.IsVisible()).ToIndexedArray(); - - foreach (var item in items) - { - if (item.Content.Id != 1178) - { - Assert.IsFalse(item.IsLast()); - } - else - { - Assert.IsTrue(item.IsLast()); - } - } - } - - [Test] - public void Is_Last_From_Where_Filter() - { - var doc = GetNode(1173); - - var items = doc - .Children - .Where(x => x.IsVisible()) - .ToIndexedArray(); - - Assert.AreEqual(4, items.Length); - - foreach (var d in items) - { - switch (d.Content.Id) - { - case 1174: - Assert.IsTrue(d.IsFirst()); - Assert.IsFalse(d.IsLast()); - break; - case 117: - Assert.IsFalse(d.IsFirst()); - Assert.IsFalse(d.IsLast()); - break; - case 1177: - Assert.IsFalse(d.IsFirst()); - Assert.IsFalse(d.IsLast()); - break; - case 1178: - Assert.IsFalse(d.IsFirst()); - Assert.IsTrue(d.IsLast()); - break; - default: - Assert.Fail("Invalid id."); - break; - } - } - } - - [PublishedModel("Home")] - internal class Home : PublishedContentModel - { - public Home(IPublishedContent content) - : base(content) - {} - } - - [PublishedModel("anything")] - internal class Anything : PublishedContentModel - { - public Anything(IPublishedContent content) - : base(content) - { } - } - - [Test] - [Ignore("Fails as long as PublishedContentModel is internal.")] // fixme - public void Is_Last_From_Where_Filter2() - { - var doc = GetNode(1173); - - var items = doc.Children - .Select(x => x.CreateModel()) // linq, returns IEnumerable - - // only way around this is to make sure every IEnumerable extension - // explicitely returns a PublishedContentSet, not an IEnumerable - - .OfType() // ours, return IEnumerable (actually a PublishedContentSet) - .Where(x => x.IsVisible()) // so, here it's linq again :-( - .ToIndexedArray(); // so, we need that one for the test to pass - - Assert.AreEqual(1, items.Length); - - foreach (var d in items) - { - switch (d.Content.Id) - { - case 1174: - Assert.IsTrue(d.IsFirst()); - Assert.IsTrue(d.IsLast()); - break; - default: - Assert.Fail("Invalid id."); - break; - } - } - } - - [Test] - public void Is_Last_From_Take() - { - var doc = GetNode(1173); - - var items = doc.Children.Take(4).ToIndexedArray(); - - foreach (var item in items) - { - if (item.Content.Id != 1178) - { - Assert.IsFalse(item.IsLast()); - } - else - { - Assert.IsTrue(item.IsLast()); - } - } - } - - [Test] - public void Is_Last_From_Skip() - { - var doc = GetNode(1173); - - foreach (var d in doc.Children.Skip(1).ToIndexedArray()) - { - if (d.Content.Id != 1176) - { - Assert.IsFalse(d.IsLast()); - } - else - { - Assert.IsTrue(d.IsLast()); - } - } - } - - [Test] - public void Is_Last_From_Concat() - { - var doc = GetNode(1173); - - var items = doc.Children - .Concat(new[] { GetNode(1175), GetNode(4444) }) - .ToIndexedArray(); - - foreach (var item in items) - { - if (item.Content.Id != 4444) - { - Assert.IsFalse(item.IsLast()); - } - else - { - Assert.IsTrue(item.IsLast()); - } - } - } - - [Test] - public void Descendants_Ordered_Properly() - { - var doc = GetNode(1046); - - var expected = new[] { 1046, 1173, 1174, 117, 1177, 1178, 1179, 1176, 1175, 4444, 1172 }; - var exindex = 0; - - // must respect the XPath descendants-or-self axis! - foreach (var d in doc.DescendantsOrSelf()) - Assert.AreEqual(expected[exindex++], d.Id); - } - - [Test] - public void Get_Property_Value_Recursive() - { - var doc = GetNode(1174); - var rVal = doc.Value("testRecursive", fallback: Fallback.ToAncestors); - var nullVal = doc.Value("DoNotFindThis", fallback: Fallback.ToAncestors); - Assert.AreEqual("This is the recursive val", rVal); - Assert.AreEqual(null, nullVal); - } - - [Test] - public void Get_Property_Value_Uses_Converter() - { - var doc = GetNode(1173); - - var propVal = doc.Value("content"); - Assert.IsInstanceOf(typeof(IHtmlString), propVal); - Assert.AreEqual("
This is some content
", propVal.ToString()); - - var propVal2 = doc.Value("content"); - Assert.IsInstanceOf(typeof(IHtmlString), propVal2); - Assert.AreEqual("
This is some content
", propVal2.ToString()); - - var propVal3 = doc.Value("Content"); - Assert.IsInstanceOf(typeof(IHtmlString), propVal3); - Assert.AreEqual("
This is some content
", propVal3.ToString()); - } - - [Test] - public void Complex_Linq() - { - var doc = GetNode(1173); - - var result = doc.Ancestors().OrderBy(x => x.Level) - .Single() - .Descendants() - .FirstOrDefault(x => x.Value("selectedNodes", defaultValue: "").Split(',').Contains("1173")); - - Assert.IsNotNull(result); - } - - [Test] - public void Children_GroupBy_DocumentTypeAlias() - { - var home = new AutoPublishedContentType(22, "Home", new PublishedPropertyType[] { }); - var custom = new AutoPublishedContentType(23, "CustomDocument", new PublishedPropertyType[] { }); - var contentTypes = new Dictionary - { - { home.Alias, home }, - { custom.Alias, custom } - }; - ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; - - var doc = GetNode(1046); - - var found1 = doc.Children.GroupBy(x => x.ContentType.Alias).ToArray(); - - Assert.AreEqual(2, found1.Length); - Assert.AreEqual(2, found1.Single(x => x.Key.ToString() == "Home").Count()); - Assert.AreEqual(1, found1.Single(x => x.Key.ToString() == "CustomDocument").Count()); - } - - [Test] - public void Children_Where_DocumentTypeAlias() - { - var home = new AutoPublishedContentType(22, "Home", new PublishedPropertyType[] { }); - var custom = new AutoPublishedContentType(23, "CustomDocument", new PublishedPropertyType[] { }); - var contentTypes = new Dictionary - { - { home.Alias, home }, - { custom.Alias, custom } - }; - ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; - - var doc = GetNode(1046); - - var found1 = doc.Children.Where(x => x.ContentType.Alias == "CustomDocument"); - var found2 = doc.Children.Where(x => x.ContentType.Alias == "Home"); - - Assert.AreEqual(1, found1.Count()); - Assert.AreEqual(2, found2.Count()); - } - - [Test] - public void Children_Order_By_Update_Date() - { - var doc = GetNode(1173); - - var ordered = doc.Children.OrderBy(x => x.UpdateDate); - - var correctOrder = new[] { 1178, 1177, 1174, 1176 }; - for (var i = 0; i < correctOrder.Length; i++) - { - Assert.AreEqual(correctOrder[i], ordered.ElementAt(i).Id); - } - - } - - [Test] - public void FirstChild() - { - var doc = GetNode(1173); // has child nodes - Assert.IsNotNull(doc.FirstChild()); - Assert.IsNotNull(doc.FirstChild(x => true)); - Assert.IsNotNull(doc.FirstChild()); - - doc = GetNode(1175); // does not have child nodes - Assert.IsNull(doc.FirstChild()); - Assert.IsNull(doc.FirstChild(x => true)); - Assert.IsNull(doc.FirstChild()); - } - - [Test] - public void FirstChildAsT() - { - var doc = GetNode(1046); // has child nodes - - var model = doc.FirstChild(x => true); // predicate - - Assert.IsNotNull(model); - Assert.IsTrue(model.Id == 1173); - Assert.IsInstanceOf(model); - Assert.IsInstanceOf(model); - - doc = GetNode(1175); // does not have child nodes - Assert.IsNull(doc.FirstChild()); - Assert.IsNull(doc.FirstChild(x => true)); - } - - [Test] - public void IsComposedOf() - { - var doc = GetNode(1173); - - var isComposedOf = doc.IsComposedOf("MyCompositionAlias"); - - Assert.IsTrue(isComposedOf); - } - - [Test] - public void HasProperty() - { - var doc = GetNode(1173); - - var hasProp = doc.HasProperty(Constants.Conventions.Content.UrlAlias); - - Assert.IsTrue(hasProp); - } - - [Test] - public void HasValue() - { - var doc = GetNode(1173); - - var hasValue = doc.HasValue(Constants.Conventions.Content.UrlAlias); - var noValue = doc.HasValue("blahblahblah"); - - Assert.IsTrue(hasValue); - Assert.IsFalse(noValue); - } - - [Test] - public void Ancestors_Where_Visible() - { - var doc = GetNode(1174); - - var whereVisible = doc.Ancestors().Where(x => x.IsVisible()); - Assert.AreEqual(1, whereVisible.Count()); - - } - - [Test] - public void Visible() - { - var hidden = GetNode(1046); - var visible = GetNode(1173); - - Assert.IsFalse(hidden.IsVisible()); - Assert.IsTrue(visible.IsVisible()); - } - - [Test] - public void Ancestor_Or_Self() - { - var doc = GetNode(1173); - - var result = doc.AncestorOrSelf(); - - Assert.IsNotNull(result); - - // ancestor-or-self has to be self! - Assert.AreEqual(1173, result.Id); - } - - [Test] - public void U4_4559() - { - var doc = GetNode(1174); - var result = doc.AncestorOrSelf(1); - Assert.IsNotNull(result); - Assert.AreEqual(1046, result.Id); - } - - [Test] - public void Ancestors_Or_Self() - { - var doc = GetNode(1174); - - var result = doc.AncestorsOrSelf().ToArray(); - - Assert.IsNotNull(result); - - Assert.AreEqual(3, result.Length); - Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1173, 1046 })); - } - - [Test] - public void Ancestors() - { - var doc = GetNode(1174); - - var result = doc.Ancestors().ToArray(); - - Assert.IsNotNull(result); - - Assert.AreEqual(2, result.Length); - Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1046 })); - } - - [Test] - public void IsAncestor() - { - // Structure: - // - Root : 1046 (no parent) - // -- Home: 1173 (parent 1046) - // -- Custom Doc: 1178 (parent 1173) - // --- Custom Doc2: 1179 (parent: 1178) - // -- Custom Doc4: 117 (parent 1173) - // - Custom Doc3: 1172 (no parent) - - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); - - Assert.IsTrue(root.IsAncestor(customDoc4)); - Assert.IsFalse(root.IsAncestor(customDoc3)); - Assert.IsTrue(root.IsAncestor(customDoc2)); - Assert.IsTrue(root.IsAncestor(customDoc)); - Assert.IsTrue(root.IsAncestor(home)); - Assert.IsFalse(root.IsAncestor(root)); - - Assert.IsTrue(home.IsAncestor(customDoc4)); - Assert.IsFalse(home.IsAncestor(customDoc3)); - Assert.IsTrue(home.IsAncestor(customDoc2)); - Assert.IsTrue(home.IsAncestor(customDoc)); - Assert.IsFalse(home.IsAncestor(home)); - Assert.IsFalse(home.IsAncestor(root)); - - Assert.IsFalse(customDoc.IsAncestor(customDoc4)); - Assert.IsFalse(customDoc.IsAncestor(customDoc3)); - Assert.IsTrue(customDoc.IsAncestor(customDoc2)); - Assert.IsFalse(customDoc.IsAncestor(customDoc)); - Assert.IsFalse(customDoc.IsAncestor(home)); - Assert.IsFalse(customDoc.IsAncestor(root)); - - Assert.IsFalse(customDoc2.IsAncestor(customDoc4)); - Assert.IsFalse(customDoc2.IsAncestor(customDoc3)); - Assert.IsFalse(customDoc2.IsAncestor(customDoc2)); - Assert.IsFalse(customDoc2.IsAncestor(customDoc)); - Assert.IsFalse(customDoc2.IsAncestor(home)); - Assert.IsFalse(customDoc2.IsAncestor(root)); - - Assert.IsFalse(customDoc3.IsAncestor(customDoc3)); - } - - [Test] - public void IsAncestorOrSelf() - { - // Structure: - // - Root : 1046 (no parent) - // -- Home: 1173 (parent 1046) - // -- Custom Doc: 1178 (parent 1173) - // --- Custom Doc2: 1179 (parent: 1178) - // -- Custom Doc4: 117 (parent 1173) - // - Custom Doc3: 1172 (no parent) - - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); - - Assert.IsTrue(root.IsAncestorOrSelf(customDoc4)); - Assert.IsFalse(root.IsAncestorOrSelf(customDoc3)); - Assert.IsTrue(root.IsAncestorOrSelf(customDoc2)); - Assert.IsTrue(root.IsAncestorOrSelf(customDoc)); - Assert.IsTrue(root.IsAncestorOrSelf(home)); - Assert.IsTrue(root.IsAncestorOrSelf(root)); - - Assert.IsTrue(home.IsAncestorOrSelf(customDoc4)); - Assert.IsFalse(home.IsAncestorOrSelf(customDoc3)); - Assert.IsTrue(home.IsAncestorOrSelf(customDoc2)); - Assert.IsTrue(home.IsAncestorOrSelf(customDoc)); - Assert.IsTrue(home.IsAncestorOrSelf(home)); - Assert.IsFalse(home.IsAncestorOrSelf(root)); - - Assert.IsFalse(customDoc.IsAncestorOrSelf(customDoc4)); - Assert.IsFalse(customDoc.IsAncestorOrSelf(customDoc3)); - Assert.IsTrue(customDoc.IsAncestorOrSelf(customDoc2)); - Assert.IsTrue(customDoc.IsAncestorOrSelf(customDoc)); - Assert.IsFalse(customDoc.IsAncestorOrSelf(home)); - Assert.IsFalse(customDoc.IsAncestorOrSelf(root)); - - Assert.IsFalse(customDoc2.IsAncestorOrSelf(customDoc4)); - Assert.IsFalse(customDoc2.IsAncestorOrSelf(customDoc3)); - Assert.IsTrue(customDoc2.IsAncestorOrSelf(customDoc2)); - Assert.IsFalse(customDoc2.IsAncestorOrSelf(customDoc)); - Assert.IsFalse(customDoc2.IsAncestorOrSelf(home)); - Assert.IsFalse(customDoc2.IsAncestorOrSelf(root)); - - Assert.IsTrue(customDoc4.IsAncestorOrSelf(customDoc4)); - Assert.IsTrue(customDoc3.IsAncestorOrSelf(customDoc3)); - } - - - [Test] - public void Descendants_Or_Self() - { - var doc = GetNode(1046); - - var result = doc.DescendantsOrSelf().ToArray(); - - Assert.IsNotNull(result); - - Assert.AreEqual(10, result.Count()); - Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 })); - } - - [Test] - public void Descendants() - { - var doc = GetNode(1046); - - var result = doc.Descendants().ToArray(); - - Assert.IsNotNull(result); - - Assert.AreEqual(9, result.Count()); - Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); - } - - [Test] - public void IsDescendant() - { - // Structure: - // - Root : 1046 (no parent) - // -- Home: 1173 (parent 1046) - // -- Custom Doc: 1178 (parent 1173) - // --- Custom Doc2: 1179 (parent: 1178) - // -- Custom Doc4: 117 (parent 1173) - // - Custom Doc3: 1172 (no parent) - - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); - - Assert.IsFalse(root.IsDescendant(root)); - Assert.IsFalse(root.IsDescendant(home)); - Assert.IsFalse(root.IsDescendant(customDoc)); - Assert.IsFalse(root.IsDescendant(customDoc2)); - Assert.IsFalse(root.IsDescendant(customDoc3)); - Assert.IsFalse(root.IsDescendant(customDoc4)); - - Assert.IsTrue(home.IsDescendant(root)); - Assert.IsFalse(home.IsDescendant(home)); - Assert.IsFalse(home.IsDescendant(customDoc)); - Assert.IsFalse(home.IsDescendant(customDoc2)); - Assert.IsFalse(home.IsDescendant(customDoc3)); - Assert.IsFalse(home.IsDescendant(customDoc4)); - - Assert.IsTrue(customDoc.IsDescendant(root)); - Assert.IsTrue(customDoc.IsDescendant(home)); - Assert.IsFalse(customDoc.IsDescendant(customDoc)); - Assert.IsFalse(customDoc.IsDescendant(customDoc2)); - Assert.IsFalse(customDoc.IsDescendant(customDoc3)); - Assert.IsFalse(customDoc.IsDescendant(customDoc4)); - - Assert.IsTrue(customDoc2.IsDescendant(root)); - Assert.IsTrue(customDoc2.IsDescendant(home)); - Assert.IsTrue(customDoc2.IsDescendant(customDoc)); - Assert.IsFalse(customDoc2.IsDescendant(customDoc2)); - Assert.IsFalse(customDoc2.IsDescendant(customDoc3)); - Assert.IsFalse(customDoc2.IsDescendant(customDoc4)); - - Assert.IsFalse(customDoc3.IsDescendant(customDoc3)); - } - - [Test] - public void IsDescendantOrSelf() - { - // Structure: - // - Root : 1046 (no parent) - // -- Home: 1173 (parent 1046) - // -- Custom Doc: 1178 (parent 1173) - // --- Custom Doc2: 1179 (parent: 1178) - // -- Custom Doc4: 117 (parent 1173) - // - Custom Doc3: 1172 (no parent) - - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); - - Assert.IsTrue(root.IsDescendantOrSelf(root)); - Assert.IsFalse(root.IsDescendantOrSelf(home)); - Assert.IsFalse(root.IsDescendantOrSelf(customDoc)); - Assert.IsFalse(root.IsDescendantOrSelf(customDoc2)); - Assert.IsFalse(root.IsDescendantOrSelf(customDoc3)); - Assert.IsFalse(root.IsDescendantOrSelf(customDoc4)); - - Assert.IsTrue(home.IsDescendantOrSelf(root)); - Assert.IsTrue(home.IsDescendantOrSelf(home)); - Assert.IsFalse(home.IsDescendantOrSelf(customDoc)); - Assert.IsFalse(home.IsDescendantOrSelf(customDoc2)); - Assert.IsFalse(home.IsDescendantOrSelf(customDoc3)); - Assert.IsFalse(home.IsDescendantOrSelf(customDoc4)); - - Assert.IsTrue(customDoc.IsDescendantOrSelf(root)); - Assert.IsTrue(customDoc.IsDescendantOrSelf(home)); - Assert.IsTrue(customDoc.IsDescendantOrSelf(customDoc)); - Assert.IsFalse(customDoc.IsDescendantOrSelf(customDoc2)); - Assert.IsFalse(customDoc.IsDescendantOrSelf(customDoc3)); - Assert.IsFalse(customDoc.IsDescendantOrSelf(customDoc4)); - - Assert.IsTrue(customDoc2.IsDescendantOrSelf(root)); - Assert.IsTrue(customDoc2.IsDescendantOrSelf(home)); - Assert.IsTrue(customDoc2.IsDescendantOrSelf(customDoc)); - Assert.IsTrue(customDoc2.IsDescendantOrSelf(customDoc2)); - Assert.IsFalse(customDoc2.IsDescendantOrSelf(customDoc3)); - Assert.IsFalse(customDoc2.IsDescendantOrSelf(customDoc4)); - - Assert.IsTrue(customDoc3.IsDescendantOrSelf(customDoc3)); - } - - [Test] - public void Up() - { - var doc = GetNode(1173); - - var result = doc.Up(); - - Assert.IsNotNull(result); - - Assert.AreEqual(1046, result.Id); - } - - [Test] - public void Down() - { - var doc = GetNode(1173); - - var result = doc.Down(); - - Assert.IsNotNull(result); - - Assert.AreEqual(1174, result.Id); - } - - [Test] - public void FragmentProperty() - { - var factory = Factory.GetInstance() as PublishedContentTypeFactory; - - var pt = factory.CreatePropertyType("detached", 1003); - var ct = factory.CreateContentType(0, "alias", new[] { pt }); - var prop = new PublishedElementPropertyBase(pt, null, false, PropertyCacheLevel.None, 5548); - Assert.IsInstanceOf(prop.GetValue()); - Assert.AreEqual(5548, prop.GetValue()); - } - - public void Fragment1() - { - var type = ContentTypesCache.Get(PublishedItemType.Content, "detachedSomething"); - var values = new Dictionary(); - var f = new PublishedElement(type, Guid.NewGuid(), values, false); - } - - [Test] - public void Fragment2() - { - var factory = Factory.GetInstance() as PublishedContentTypeFactory; - - var pt1 = factory.CreatePropertyType("legend", 1004); - var pt2 = factory.CreatePropertyType("image", 1005); - var pt3 = factory.CreatePropertyType("size", 1003); - const string val1 = "boom bam"; - const int val2 = 0; - const int val3 = 666; - - var guid = Guid.NewGuid(); - - var ct = factory.CreateContentType(0, "alias", new[] { pt1, pt2, pt3 }); - - var c = new ImageWithLegendModel(ct, guid, new Dictionary - { - { "legend", val1 }, - { "image", val2 }, - { "size", val3 }, - }, false); - - Assert.AreEqual(val1, c.Legend); - Assert.AreEqual(val3, c.Size); - } - - class ImageWithLegendModel : PublishedElement - { - public ImageWithLegendModel(PublishedContentType contentType, Guid fragmentKey, Dictionary values, bool previewing) - : base(contentType, fragmentKey, values, previewing) - { } - - - public string Legend => this.Value("legend"); - - public IPublishedContent Image => this.Value("image"); - - public int Size => this.Value("size"); - } - } -} +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Web; +//using NUnit.Framework; +//using Umbraco.Core; +//using Umbraco.Core.Models.PublishedContent; +//using Umbraco.Core.PropertyEditors; +//using Umbraco.Web; +//using Umbraco.Web.PublishedCache; +//using Umbraco.Core.Composing; +//using Moq; +//using Umbraco.Core.Cache; +//using Umbraco.Core.Configuration; +//using Umbraco.Core.Logging; +//using Umbraco.Core.Models; +//using Umbraco.Core.Services; +//using Umbraco.Tests.TestHelpers; +//using Umbraco.Tests.Testing; +//using Umbraco.Web.Models.PublishedContent; +//using Umbraco.Web.PropertyEditors; +// +//namespace Umbraco.Tests.PublishedContent +//{ +// /// +// /// Tests the methods on IPublishedContent using the DefaultPublishedContentStore +// /// +// [TestFixture] +// [UmbracoTest(TypeLoader = UmbracoTestOptions.TypeLoader.PerFixture)] +// public class PublishedContentTests : PublishedContentTestBase +// { +// protected override void Compose() +// { +// base.Compose(); +// +// Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes())); +// Composition.RegisterUnique(); +// Composition.RegisterUnique(); +// +// var logger = Mock.Of(); +// var dataTypeService = new TestObjects.TestDataTypeService( +// new DataType(new VoidEditor(logger)) { Id = 1 }, +// new DataType(new TrueFalsePropertyEditor(logger)) { Id = 1001 }, +// new DataType(new RichTextPropertyEditor(logger)) { Id = 1002 }, +// new DataType(new IntegerPropertyEditor(logger)) { Id = 1003 }, +// new DataType(new TextboxPropertyEditor(logger)) { Id = 1004 }, +// new DataType(new MediaPickerPropertyEditor(logger)) { Id = 1005 }); +// Composition.RegisterUnique(f => dataTypeService); +// } +// +// protected override void Initialize() +// { +// base.Initialize(); +// +// var factory = Factory.GetInstance() as PublishedContentTypeFactory; +// +// // need to specify a custom callback for unit tests +// // AutoPublishedContentTypes generates properties automatically +// // when they are requested, but we must declare those that we +// // explicitely want to be here... +// +// var propertyTypes = new[] +// { +// // AutoPublishedContentType will auto-generate other properties +// factory.CreatePropertyType("umbracoNaviHide", 1001), +// factory.CreatePropertyType("selectedNodes", 1), +// factory.CreatePropertyType("umbracoUrlAlias", 1), +// factory.CreatePropertyType("content", 1002), +// factory.CreatePropertyType("testRecursive", 1), +// }; +// var compositionAliases = new[] { "MyCompositionAlias" }; +// var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes); +// ContentTypesCache.GetPublishedContentTypeByAlias = alias => type; +// } +// +// protected override TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) +// { +// var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger); +// +// // this is so the model factory looks into the test assembly +// pluginManager.AssembliesToScan = pluginManager.AssembliesToScan +// .Union(new[] { typeof(PublishedContentTests).Assembly }) +// .ToList(); +// +// return pluginManager; +// } +// +// private readonly Guid _node1173Guid = Guid.NewGuid(); +// +// protected override string GetXmlContent(int templateId) +// { +// return @" +// +// +// +// +//]> +// +// +// +// +// 1 +// +// +// This is some content]]> +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// 1 +// +// +// +// +// +// +// +// +// +//"; +// } +// +// internal IPublishedContent GetNode(int id) +// { +// var ctx = GetUmbracoContext("/test"); +// var doc = ctx.ContentCache.GetById(id); +// Assert.IsNotNull(doc); +// return doc; +// } +// +// [Test] +// public void GetNodeByIds() +// { +// var ctx = GetUmbracoContext("/test"); +// var contentById = ctx.ContentCache.GetById(1173); +// Assert.IsNotNull(contentById); +// var contentByGuid = ctx.ContentCache.GetById(_node1173Guid); +// Assert.IsNotNull(contentByGuid); +// Assert.AreEqual(contentById.Id, contentByGuid.Id); +// Assert.AreEqual(contentById.Key, contentByGuid.Key); +// +// contentById = ctx.ContentCache.GetById(666); +// Assert.IsNull(contentById); +// contentByGuid = ctx.ContentCache.GetById(Guid.NewGuid()); +// Assert.IsNull(contentByGuid); +// } +// +// [Test] +// public void Is_Last_From_Where_Filter_Dynamic_Linq() +// { +// var doc = GetNode(1173); +// +// var items = doc.Children.Where(x => x.IsVisible()).ToIndexedArray(); +// +// foreach (var item in items) +// { +// if (item.Content.Id != 1178) +// { +// Assert.IsFalse(item.IsLast()); +// } +// else +// { +// Assert.IsTrue(item.IsLast()); +// } +// } +// } +// +// [Test] +// public void Is_Last_From_Where_Filter() +// { +// var doc = GetNode(1173); +// +// var items = doc +// .Children +// .Where(x => x.IsVisible()) +// .ToIndexedArray(); +// +// Assert.AreEqual(4, items.Length); +// +// foreach (var d in items) +// { +// switch (d.Content.Id) +// { +// case 1174: +// Assert.IsTrue(d.IsFirst()); +// Assert.IsFalse(d.IsLast()); +// break; +// case 117: +// Assert.IsFalse(d.IsFirst()); +// Assert.IsFalse(d.IsLast()); +// break; +// case 1177: +// Assert.IsFalse(d.IsFirst()); +// Assert.IsFalse(d.IsLast()); +// break; +// case 1178: +// Assert.IsFalse(d.IsFirst()); +// Assert.IsTrue(d.IsLast()); +// break; +// default: +// Assert.Fail("Invalid id."); +// break; +// } +// } +// } +// +// [PublishedModel("Home")] +// internal class Home : PublishedContentModel +// { +// public Home(IPublishedContent content) +// : base(content) +// {} +// } +// +// [PublishedModel("anything")] +// internal class Anything : PublishedContentModel +// { +// public Anything(IPublishedContent content) +// : base(content) +// { } +// } +// +// [Test] +// [Ignore("Fails as long as PublishedContentModel is internal.")] // fixme +// public void Is_Last_From_Where_Filter2() +// { +// var doc = GetNode(1173); +// +// var items = doc.Children +// .Select(x => x.CreateModel()) // linq, returns IEnumerable +// +// // only way around this is to make sure every IEnumerable extension +// // explicitely returns a PublishedContentSet, not an IEnumerable +// +// .OfType() // ours, return IEnumerable (actually a PublishedContentSet) +// .Where(x => x.IsVisible()) // so, here it's linq again :-( +// .ToIndexedArray(); // so, we need that one for the test to pass +// +// Assert.AreEqual(1, items.Length); +// +// foreach (var d in items) +// { +// switch (d.Content.Id) +// { +// case 1174: +// Assert.IsTrue(d.IsFirst()); +// Assert.IsTrue(d.IsLast()); +// break; +// default: +// Assert.Fail("Invalid id."); +// break; +// } +// } +// } +// +// [Test] +// public void Is_Last_From_Take() +// { +// var doc = GetNode(1173); +// +// var items = doc.Children.Take(4).ToIndexedArray(); +// +// foreach (var item in items) +// { +// if (item.Content.Id != 1178) +// { +// Assert.IsFalse(item.IsLast()); +// } +// else +// { +// Assert.IsTrue(item.IsLast()); +// } +// } +// } +// +// [Test] +// public void Is_Last_From_Skip() +// { +// var doc = GetNode(1173); +// +// foreach (var d in doc.Children.Skip(1).ToIndexedArray()) +// { +// if (d.Content.Id != 1176) +// { +// Assert.IsFalse(d.IsLast()); +// } +// else +// { +// Assert.IsTrue(d.IsLast()); +// } +// } +// } +// +// [Test] +// public void Is_Last_From_Concat() +// { +// var doc = GetNode(1173); +// +// var items = doc.Children +// .Concat(new[] { GetNode(1175), GetNode(4444) }) +// .ToIndexedArray(); +// +// foreach (var item in items) +// { +// if (item.Content.Id != 4444) +// { +// Assert.IsFalse(item.IsLast()); +// } +// else +// { +// Assert.IsTrue(item.IsLast()); +// } +// } +// } +// +// [Test] +// public void Descendants_Ordered_Properly() +// { +// var doc = GetNode(1046); +// +// var expected = new[] { 1046, 1173, 1174, 117, 1177, 1178, 1179, 1176, 1175, 4444, 1172 }; +// var exindex = 0; +// +// // must respect the XPath descendants-or-self axis! +// foreach (var d in doc.DescendantsOrSelf()) +// Assert.AreEqual(expected[exindex++], d.Id); +// } +// +// [Test] +// public void Get_Property_Value_Recursive() +// { +// var doc = GetNode(1174); +// var rVal = doc.Value("testRecursive", fallback: Fallback.ToAncestors); +// var nullVal = doc.Value("DoNotFindThis", fallback: Fallback.ToAncestors); +// Assert.AreEqual("This is the recursive val", rVal); +// Assert.AreEqual(null, nullVal); +// } +// +// [Test] +// public void Get_Property_Value_Uses_Converter() +// { +// var doc = GetNode(1173); +// +// var propVal = doc.Value("content"); +// Assert.IsInstanceOf(typeof(IHtmlString), propVal); +// Assert.AreEqual("
This is some content
", propVal.ToString()); +// +// var propVal2 = doc.Value("content"); +// Assert.IsInstanceOf(typeof(IHtmlString), propVal2); +// Assert.AreEqual("
This is some content
", propVal2.ToString()); +// +// var propVal3 = doc.Value("Content"); +// Assert.IsInstanceOf(typeof(IHtmlString), propVal3); +// Assert.AreEqual("
This is some content
", propVal3.ToString()); +// } +// +// [Test] +// public void Complex_Linq() +// { +// var doc = GetNode(1173); +// +// var result = doc.Ancestors().OrderBy(x => x.Level) +// .Single() +// .Descendants() +// .FirstOrDefault(x => x.Value("selectedNodes", defaultValue: "").Split(',').Contains("1173")); +// +// Assert.IsNotNull(result); +// } +// +// [Test] +// public void Children_GroupBy_DocumentTypeAlias() +// { +// var home = new AutoPublishedContentType(22, "Home", new PublishedPropertyType[] { }); +// var custom = new AutoPublishedContentType(23, "CustomDocument", new PublishedPropertyType[] { }); +// var contentTypes = new Dictionary +// { +// { home.Alias, home }, +// { custom.Alias, custom } +// }; +// ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; +// +// var doc = GetNode(1046); +// +// var found1 = doc.Children.GroupBy(x => x.ContentType.Alias).ToArray(); +// +// Assert.AreEqual(2, found1.Length); +// Assert.AreEqual(2, found1.Single(x => x.Key.ToString() == "Home").Count()); +// Assert.AreEqual(1, found1.Single(x => x.Key.ToString() == "CustomDocument").Count()); +// } +// +// [Test] +// public void Children_Where_DocumentTypeAlias() +// { +// var home = new AutoPublishedContentType(22, "Home", new PublishedPropertyType[] { }); +// var custom = new AutoPublishedContentType(23, "CustomDocument", new PublishedPropertyType[] { }); +// var contentTypes = new Dictionary +// { +// { home.Alias, home }, +// { custom.Alias, custom } +// }; +// ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; +// +// var doc = GetNode(1046); +// +// var found1 = doc.Children.Where(x => x.ContentType.Alias == "CustomDocument"); +// var found2 = doc.Children.Where(x => x.ContentType.Alias == "Home"); +// +// Assert.AreEqual(1, found1.Count()); +// Assert.AreEqual(2, found2.Count()); +// } +// +// [Test] +// public void Children_Order_By_Update_Date() +// { +// var doc = GetNode(1173); +// +// var ordered = doc.Children.OrderBy(x => x.UpdateDate); +// +// var correctOrder = new[] { 1178, 1177, 1174, 1176 }; +// for (var i = 0; i < correctOrder.Length; i++) +// { +// Assert.AreEqual(correctOrder[i], ordered.ElementAt(i).Id); +// } +// +// } +// +// [Test] +// public void FirstChild() +// { +// var doc = GetNode(1173); // has child nodes +// Assert.IsNotNull(doc.FirstChild()); +// Assert.IsNotNull(doc.FirstChild(x => true)); +// Assert.IsNotNull(doc.FirstChild()); +// +// doc = GetNode(1175); // does not have child nodes +// Assert.IsNull(doc.FirstChild()); +// Assert.IsNull(doc.FirstChild(x => true)); +// Assert.IsNull(doc.FirstChild()); +// } +// +// [Test] +// public void FirstChildAsT() +// { +// var doc = GetNode(1046); // has child nodes +// +// var model = doc.FirstChild(x => true); // predicate +// +// Assert.IsNotNull(model); +// Assert.IsTrue(model.Id == 1173); +// Assert.IsInstanceOf(model); +// Assert.IsInstanceOf(model); +// +// doc = GetNode(1175); // does not have child nodes +// Assert.IsNull(doc.FirstChild()); +// Assert.IsNull(doc.FirstChild(x => true)); +// } +// +// [Test] +// public void IsComposedOf() +// { +// var doc = GetNode(1173); +// +// var isComposedOf = doc.IsComposedOf("MyCompositionAlias"); +// +// Assert.IsTrue(isComposedOf); +// } +// +// [Test] +// public void HasProperty() +// { +// var doc = GetNode(1173); +// +// var hasProp = doc.HasProperty(Constants.Conventions.Content.UrlAlias); +// +// Assert.IsTrue(hasProp); +// } +// +// [Test] +// public void HasValue() +// { +// var doc = GetNode(1173); +// +// var hasValue = doc.HasValue(Constants.Conventions.Content.UrlAlias); +// var noValue = doc.HasValue("blahblahblah"); +// +// Assert.IsTrue(hasValue); +// Assert.IsFalse(noValue); +// } +// +// [Test] +// public void Ancestors_Where_Visible() +// { +// var doc = GetNode(1174); +// +// var whereVisible = doc.Ancestors().Where(x => x.IsVisible()); +// Assert.AreEqual(1, whereVisible.Count()); +// +// } +// +// [Test] +// public void Visible() +// { +// var hidden = GetNode(1046); +// var visible = GetNode(1173); +// +// Assert.IsFalse(hidden.IsVisible()); +// Assert.IsTrue(visible.IsVisible()); +// } +// +// [Test] +// public void Ancestor_Or_Self() +// { +// var doc = GetNode(1173); +// +// var result = doc.AncestorOrSelf(); +// +// Assert.IsNotNull(result); +// +// // ancestor-or-self has to be self! +// Assert.AreEqual(1173, result.Id); +// } +// +// [Test] +// public void U4_4559() +// { +// var doc = GetNode(1174); +// var result = doc.AncestorOrSelf(1); +// Assert.IsNotNull(result); +// Assert.AreEqual(1046, result.Id); +// } +// +// [Test] +// public void Ancestors_Or_Self() +// { +// var doc = GetNode(1174); +// +// var result = doc.AncestorsOrSelf().ToArray(); +// +// Assert.IsNotNull(result); +// +// Assert.AreEqual(3, result.Length); +// Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1173, 1046 })); +// } +// +// [Test] +// public void Ancestors() +// { +// var doc = GetNode(1174); +// +// var result = doc.Ancestors().ToArray(); +// +// Assert.IsNotNull(result); +// +// Assert.AreEqual(2, result.Length); +// Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1046 })); +// } +// +// [Test] +// public void IsAncestor() +// { +// // Structure: +// // - Root : 1046 (no parent) +// // -- Home: 1173 (parent 1046) +// // -- Custom Doc: 1178 (parent 1173) +// // --- Custom Doc2: 1179 (parent: 1178) +// // -- Custom Doc4: 117 (parent 1173) +// // - Custom Doc3: 1172 (no parent) +// +// var home = GetNode(1173); +// var root = GetNode(1046); +// var customDoc = GetNode(1178); +// var customDoc2 = GetNode(1179); +// var customDoc3 = GetNode(1172); +// var customDoc4 = GetNode(117); +// +// Assert.IsTrue(root.IsAncestor(customDoc4)); +// Assert.IsFalse(root.IsAncestor(customDoc3)); +// Assert.IsTrue(root.IsAncestor(customDoc2)); +// Assert.IsTrue(root.IsAncestor(customDoc)); +// Assert.IsTrue(root.IsAncestor(home)); +// Assert.IsFalse(root.IsAncestor(root)); +// +// Assert.IsTrue(home.IsAncestor(customDoc4)); +// Assert.IsFalse(home.IsAncestor(customDoc3)); +// Assert.IsTrue(home.IsAncestor(customDoc2)); +// Assert.IsTrue(home.IsAncestor(customDoc)); +// Assert.IsFalse(home.IsAncestor(home)); +// Assert.IsFalse(home.IsAncestor(root)); +// +// Assert.IsFalse(customDoc.IsAncestor(customDoc4)); +// Assert.IsFalse(customDoc.IsAncestor(customDoc3)); +// Assert.IsTrue(customDoc.IsAncestor(customDoc2)); +// Assert.IsFalse(customDoc.IsAncestor(customDoc)); +// Assert.IsFalse(customDoc.IsAncestor(home)); +// Assert.IsFalse(customDoc.IsAncestor(root)); +// +// Assert.IsFalse(customDoc2.IsAncestor(customDoc4)); +// Assert.IsFalse(customDoc2.IsAncestor(customDoc3)); +// Assert.IsFalse(customDoc2.IsAncestor(customDoc2)); +// Assert.IsFalse(customDoc2.IsAncestor(customDoc)); +// Assert.IsFalse(customDoc2.IsAncestor(home)); +// Assert.IsFalse(customDoc2.IsAncestor(root)); +// +// Assert.IsFalse(customDoc3.IsAncestor(customDoc3)); +// } +// +// [Test] +// public void IsAncestorOrSelf() +// { +// // Structure: +// // - Root : 1046 (no parent) +// // -- Home: 1173 (parent 1046) +// // -- Custom Doc: 1178 (parent 1173) +// // --- Custom Doc2: 1179 (parent: 1178) +// // -- Custom Doc4: 117 (parent 1173) +// // - Custom Doc3: 1172 (no parent) +// +// var home = GetNode(1173); +// var root = GetNode(1046); +// var customDoc = GetNode(1178); +// var customDoc2 = GetNode(1179); +// var customDoc3 = GetNode(1172); +// var customDoc4 = GetNode(117); +// +// Assert.IsTrue(root.IsAncestorOrSelf(customDoc4)); +// Assert.IsFalse(root.IsAncestorOrSelf(customDoc3)); +// Assert.IsTrue(root.IsAncestorOrSelf(customDoc2)); +// Assert.IsTrue(root.IsAncestorOrSelf(customDoc)); +// Assert.IsTrue(root.IsAncestorOrSelf(home)); +// Assert.IsTrue(root.IsAncestorOrSelf(root)); +// +// Assert.IsTrue(home.IsAncestorOrSelf(customDoc4)); +// Assert.IsFalse(home.IsAncestorOrSelf(customDoc3)); +// Assert.IsTrue(home.IsAncestorOrSelf(customDoc2)); +// Assert.IsTrue(home.IsAncestorOrSelf(customDoc)); +// Assert.IsTrue(home.IsAncestorOrSelf(home)); +// Assert.IsFalse(home.IsAncestorOrSelf(root)); +// +// Assert.IsFalse(customDoc.IsAncestorOrSelf(customDoc4)); +// Assert.IsFalse(customDoc.IsAncestorOrSelf(customDoc3)); +// Assert.IsTrue(customDoc.IsAncestorOrSelf(customDoc2)); +// Assert.IsTrue(customDoc.IsAncestorOrSelf(customDoc)); +// Assert.IsFalse(customDoc.IsAncestorOrSelf(home)); +// Assert.IsFalse(customDoc.IsAncestorOrSelf(root)); +// +// Assert.IsFalse(customDoc2.IsAncestorOrSelf(customDoc4)); +// Assert.IsFalse(customDoc2.IsAncestorOrSelf(customDoc3)); +// Assert.IsTrue(customDoc2.IsAncestorOrSelf(customDoc2)); +// Assert.IsFalse(customDoc2.IsAncestorOrSelf(customDoc)); +// Assert.IsFalse(customDoc2.IsAncestorOrSelf(home)); +// Assert.IsFalse(customDoc2.IsAncestorOrSelf(root)); +// +// Assert.IsTrue(customDoc4.IsAncestorOrSelf(customDoc4)); +// Assert.IsTrue(customDoc3.IsAncestorOrSelf(customDoc3)); +// } +// +// +// [Test] +// public void Descendants_Or_Self() +// { +// var doc = GetNode(1046); +// +// var result = doc.DescendantsOrSelf().ToArray(); +// +// Assert.IsNotNull(result); +// +// Assert.AreEqual(10, result.Count()); +// Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 })); +// } +// +// [Test] +// public void Descendants() +// { +// var doc = GetNode(1046); +// +// var result = doc.Descendants().ToArray(); +// +// Assert.IsNotNull(result); +// +// Assert.AreEqual(9, result.Count()); +// Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); +// } +// +// [Test] +// public void IsDescendant() +// { +// // Structure: +// // - Root : 1046 (no parent) +// // -- Home: 1173 (parent 1046) +// // -- Custom Doc: 1178 (parent 1173) +// // --- Custom Doc2: 1179 (parent: 1178) +// // -- Custom Doc4: 117 (parent 1173) +// // - Custom Doc3: 1172 (no parent) +// +// var home = GetNode(1173); +// var root = GetNode(1046); +// var customDoc = GetNode(1178); +// var customDoc2 = GetNode(1179); +// var customDoc3 = GetNode(1172); +// var customDoc4 = GetNode(117); +// +// Assert.IsFalse(root.IsDescendant(root)); +// Assert.IsFalse(root.IsDescendant(home)); +// Assert.IsFalse(root.IsDescendant(customDoc)); +// Assert.IsFalse(root.IsDescendant(customDoc2)); +// Assert.IsFalse(root.IsDescendant(customDoc3)); +// Assert.IsFalse(root.IsDescendant(customDoc4)); +// +// Assert.IsTrue(home.IsDescendant(root)); +// Assert.IsFalse(home.IsDescendant(home)); +// Assert.IsFalse(home.IsDescendant(customDoc)); +// Assert.IsFalse(home.IsDescendant(customDoc2)); +// Assert.IsFalse(home.IsDescendant(customDoc3)); +// Assert.IsFalse(home.IsDescendant(customDoc4)); +// +// Assert.IsTrue(customDoc.IsDescendant(root)); +// Assert.IsTrue(customDoc.IsDescendant(home)); +// Assert.IsFalse(customDoc.IsDescendant(customDoc)); +// Assert.IsFalse(customDoc.IsDescendant(customDoc2)); +// Assert.IsFalse(customDoc.IsDescendant(customDoc3)); +// Assert.IsFalse(customDoc.IsDescendant(customDoc4)); +// +// Assert.IsTrue(customDoc2.IsDescendant(root)); +// Assert.IsTrue(customDoc2.IsDescendant(home)); +// Assert.IsTrue(customDoc2.IsDescendant(customDoc)); +// Assert.IsFalse(customDoc2.IsDescendant(customDoc2)); +// Assert.IsFalse(customDoc2.IsDescendant(customDoc3)); +// Assert.IsFalse(customDoc2.IsDescendant(customDoc4)); +// +// Assert.IsFalse(customDoc3.IsDescendant(customDoc3)); +// } +// +// [Test] +// public void IsDescendantOrSelf() +// { +// // Structure: +// // - Root : 1046 (no parent) +// // -- Home: 1173 (parent 1046) +// // -- Custom Doc: 1178 (parent 1173) +// // --- Custom Doc2: 1179 (parent: 1178) +// // -- Custom Doc4: 117 (parent 1173) +// // - Custom Doc3: 1172 (no parent) +// +// var home = GetNode(1173); +// var root = GetNode(1046); +// var customDoc = GetNode(1178); +// var customDoc2 = GetNode(1179); +// var customDoc3 = GetNode(1172); +// var customDoc4 = GetNode(117); +// +// Assert.IsTrue(root.IsDescendantOrSelf(root)); +// Assert.IsFalse(root.IsDescendantOrSelf(home)); +// Assert.IsFalse(root.IsDescendantOrSelf(customDoc)); +// Assert.IsFalse(root.IsDescendantOrSelf(customDoc2)); +// Assert.IsFalse(root.IsDescendantOrSelf(customDoc3)); +// Assert.IsFalse(root.IsDescendantOrSelf(customDoc4)); +// +// Assert.IsTrue(home.IsDescendantOrSelf(root)); +// Assert.IsTrue(home.IsDescendantOrSelf(home)); +// Assert.IsFalse(home.IsDescendantOrSelf(customDoc)); +// Assert.IsFalse(home.IsDescendantOrSelf(customDoc2)); +// Assert.IsFalse(home.IsDescendantOrSelf(customDoc3)); +// Assert.IsFalse(home.IsDescendantOrSelf(customDoc4)); +// +// Assert.IsTrue(customDoc.IsDescendantOrSelf(root)); +// Assert.IsTrue(customDoc.IsDescendantOrSelf(home)); +// Assert.IsTrue(customDoc.IsDescendantOrSelf(customDoc)); +// Assert.IsFalse(customDoc.IsDescendantOrSelf(customDoc2)); +// Assert.IsFalse(customDoc.IsDescendantOrSelf(customDoc3)); +// Assert.IsFalse(customDoc.IsDescendantOrSelf(customDoc4)); +// +// Assert.IsTrue(customDoc2.IsDescendantOrSelf(root)); +// Assert.IsTrue(customDoc2.IsDescendantOrSelf(home)); +// Assert.IsTrue(customDoc2.IsDescendantOrSelf(customDoc)); +// Assert.IsTrue(customDoc2.IsDescendantOrSelf(customDoc2)); +// Assert.IsFalse(customDoc2.IsDescendantOrSelf(customDoc3)); +// Assert.IsFalse(customDoc2.IsDescendantOrSelf(customDoc4)); +// +// Assert.IsTrue(customDoc3.IsDescendantOrSelf(customDoc3)); +// } +// +// [Test] +// public void Up() +// { +// var doc = GetNode(1173); +// +// var result = doc.Up(); +// +// Assert.IsNotNull(result); +// +// Assert.AreEqual(1046, result.Id); +// } +// +// [Test] +// public void Down() +// { +// var doc = GetNode(1173); +// +// var result = doc.Down(); +// +// Assert.IsNotNull(result); +// +// Assert.AreEqual(1174, result.Id); +// } +// +// [Test] +// public void FragmentProperty() +// { +// var factory = Factory.GetInstance() as PublishedContentTypeFactory; +// +// var pt = factory.CreatePropertyType("detached", 1003); +// var ct = factory.CreateContentType(0, "alias", new[] { pt }); +// var prop = new PublishedElementPropertyBase(pt, null, false, PropertyCacheLevel.None, 5548); +// Assert.IsInstanceOf(prop.GetValue()); +// Assert.AreEqual(5548, prop.GetValue()); +// } +// +// public void Fragment1() +// { +// var type = ContentTypesCache.Get(PublishedItemType.Content, "detachedSomething"); +// var values = new Dictionary(); +// var f = new PublishedElement(type, Guid.NewGuid(), values, false); +// } +// +// [Test] +// public void Fragment2() +// { +// var factory = Factory.GetInstance() as PublishedContentTypeFactory; +// +// var pt1 = factory.CreatePropertyType("legend", 1004); +// var pt2 = factory.CreatePropertyType("image", 1005); +// var pt3 = factory.CreatePropertyType("size", 1003); +// const string val1 = "boom bam"; +// const int val2 = 0; +// const int val3 = 666; +// +// var guid = Guid.NewGuid(); +// +// var ct = factory.CreateContentType(0, "alias", new[] { pt1, pt2, pt3 }); +// +// var c = new ImageWithLegendModel(ct, guid, new Dictionary +// { +// { "legend", val1 }, +// { "image", val2 }, +// { "size", val3 }, +// }, false); +// +// Assert.AreEqual(val1, c.Legend); +// Assert.AreEqual(val3, c.Size); +// } +// +// class ImageWithLegendModel : PublishedElement +// { +// public ImageWithLegendModel(PublishedContentType contentType, Guid fragmentKey, Dictionary values, bool previewing) +// : base(contentType, fragmentKey, values, previewing) +// { } +// +// +// public string Legend => this.Value("legend"); +// +// public IPublishedContent Image => this.Value("image"); +// +// public int Size => this.Value("size"); +// } +// } +//} diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 88b211d0ee..f88f37a972 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -1,508 +1,508 @@ -using System.Web; -using System.Xml.Linq; -using System.Xml.XPath; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.UmbracoExamine; -using Umbraco.Web; -using Umbraco.Web.PublishedCache.XmlPublishedCache; -using System.Linq; -using System.Threading; -using System.Xml; -using Examine; -using Umbraco.Core.Cache; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Strings; -using Umbraco.Examine; -using Current = Umbraco.Web.Composing.Current; -using Umbraco.Tests.Testing; -using Umbraco.Core.Composing; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.PropertyEditors; - -namespace Umbraco.Tests.PublishedContent -{ - /// - /// Tests the typed extension methods on IPublishedContent using the DefaultPublishedMediaStore - /// - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] - public class PublishedMediaTests : PublishedContentTestBase - { - /// - /// sets up resolvers before resolution is frozen - /// - protected override void Compose() - { - base.Compose(); - - Composition.WithCollectionBuilder() - .Clear() - .Append(); - } - - private IMediaType MakeNewMediaType(IUser user, string text, int parentId = -1) - { - var mt = new MediaType(parentId) { Name = text, Alias = text, Thumbnail = "icon-folder", Icon = "icon-folder" }; - ServiceContext.MediaTypeService.Save(mt); - return mt; - } - - private IMedia MakeNewMedia(string name, IMediaType mediaType, IUser user, int parentId) - { - var m = ServiceContext.MediaService.CreateMediaWithIdentity(name, parentId, mediaType.Alias); - return m; - } - - /// - /// Shared with PublishMediaStoreTests - /// - /// - /// - /// - internal IPublishedContent GetNode(int id, UmbracoContext umbracoContext) - { - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new StaticCacheProvider(), ContentTypesCache); - var doc = cache.GetById(id); - Assert.IsNotNull(doc); - return doc; - } - - private IPublishedContent GetNode(int id) - { - return GetNode(id, GetUmbracoContext("/test")); - } - - [Test] - public void Get_Property_Value_Uses_Converter() - { - var mType = MockedContentTypes.CreateImageMediaType("image2"); - //lets add an RTE to this - mType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType("test", ValueStorageType.Nvarchar, "content") - { - Name = "Rich Text", - DataTypeId = -87 //tiny mce - }); - ServiceContext.MediaTypeService.Save(mType); - var media = MockedMedia.CreateMediaImage(mType, -1); - media.Properties["content"].SetValue("
This is some content
"); - ServiceContext.MediaService.Save(media); - - var publishedMedia = GetNode(media.Id); - - var propVal = publishedMedia.Value("content"); - Assert.IsInstanceOf(propVal); - Assert.AreEqual("
This is some content
", propVal.ToString()); - - var propVal2 = publishedMedia.Value("content"); - Assert.IsInstanceOf(propVal2); - Assert.AreEqual("
This is some content
", propVal2.ToString()); - - var propVal3 = publishedMedia.Value("Content"); - Assert.IsInstanceOf(propVal3); - Assert.AreEqual("
This is some content
", propVal3.ToString()); - } - - [Test] - public void Ensure_Children_Sorted_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootChildren = publishedMedia.Children().ToArray(); - var currSort = 0; - for (var i = 0; i < rootChildren.Count(); i++) - { - Assert.GreaterOrEqual(rootChildren[i].SortOrder, currSort); - currSort = rootChildren[i].SortOrder; - } - } - } - - [Test] - public void Do_Not_Find_In_Recycle_Bin() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - //include unpublished content since this uses the 'internal' indexer, it's up to the media cache to filter - validator: new ContentValueSetValidator(false))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //ensure it is found - var publishedMedia = cache.GetById(3113); - Assert.IsNotNull(publishedMedia); - - //move item to recycle bin - var newXml = XElement.Parse(@" - - 115 - 268 - 10726 - jpg - "); - indexer.IndexItems(new[]{ newXml.ConvertToValueSet("media") }); - - - //ensure it still exists in the index (raw examine search) - var criteria = searcher.CreateQuery(); - var filter = criteria.Id(3113); - var found = filter.Execute(); - Assert.IsNotNull(found); - Assert.AreEqual(1, found.TotalItemCount); - - //ensure it does not show up in the published media store - var recycledMedia = cache.GetById(3113); - Assert.IsNull(recycledMedia); - - } - - } - - [Test] - public void Children_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootChildren = publishedMedia.Children(); - Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { 2222, 1113, 1114, 1115, 1116 })); - - var publishedChild1 = cache.GetById(2222); - var subChildren = publishedChild1.Children(); - Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { 2112 })); - } - } - - [Test] - public void Descendants_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootDescendants = publishedMedia.Descendants(); - Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1113, 1114, 1115, 1116 })); - - var publishedChild1 = cache.GetById(2222); - var subDescendants = publishedChild1.Descendants(); - Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 3113 })); - } - } - - [Test] - public void DescendantsOrSelf_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootDescendants = publishedMedia.DescendantsOrSelf(); - Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 1111, 2112, 2222, 1113, 1114, 1115, 1116 })); - - var publishedChild1 = cache.GetById(2222); - var subDescendants = publishedChild1.DescendantsOrSelf(); - Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2222, 2112, 3113 })); - } - } - - [Test] - public void Ancestors_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var ctx = GetUmbracoContext("/test"); - var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(3113); - var ancestors = publishedMedia.Ancestors(); - Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1111 })); - } - - } - - [Test] - public void AncestorsOrSelf_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - - var ctx = GetUmbracoContext("/test"); - var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(3113); - var ancestors = publishedMedia.AncestorsOrSelf(); - Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 3113, 2112, 2222, 1111 })); - } - } - - [Test] - public void Children_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedMedia = GetNode(mRoot.Id); - var rootChildren = publishedMedia.Children(); - Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mChild2.Id, mChild3.Id })); - - var publishedChild1 = GetNode(mChild1.Id); - var subChildren = publishedChild1.Children(); - Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - } - - [Test] - public void Descendants_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedMedia = GetNode(mRoot.Id); - var rootDescendants = publishedMedia.Descendants(); - Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mChild2.Id, mChild3.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - - var publishedChild1 = GetNode(mChild1.Id); - var subDescendants = publishedChild1.Descendants(); - Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - } - - [Test] - public void DescendantsOrSelf_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedMedia = GetNode(mRoot.Id); - var rootDescendantsOrSelf = publishedMedia.DescendantsOrSelf(); - Assert.IsTrue(rootDescendantsOrSelf.Select(x => x.Id).ContainsAll( - new[] { mRoot.Id, mChild1.Id, mChild2.Id, mChild3.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - - var publishedChild1 = GetNode(mChild1.Id); - var subDescendantsOrSelf = publishedChild1.DescendantsOrSelf(); - Assert.IsTrue(subDescendantsOrSelf.Select(x => x.Id).ContainsAll( - new[] { mChild1.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - } - - [Test] - public void Parent_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedRoot = GetNode(mRoot.Id); - Assert.AreEqual(null, publishedRoot.Parent); - - var publishedChild1 = GetNode(mChild1.Id); - Assert.AreEqual(mRoot.Id, publishedChild1.Parent.Id); - - var publishedSubChild1 = GetNode(mSubChild1.Id); - Assert.AreEqual(mChild1.Id, publishedSubChild1.Parent.Id); - } - - [Test] - public void Ancestors_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedSubChild1 = GetNode(mSubChild1.Id); - Assert.IsTrue(publishedSubChild1.Ancestors().Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mRoot.Id })); - } - - [Test] - public void AncestorsOrSelf_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedSubChild1 = GetNode(mSubChild1.Id); - Assert.IsTrue(publishedSubChild1.AncestorsOrSelf().Select(x => x.Id).ContainsAll( - new[] { mSubChild1.Id, mChild1.Id, mRoot.Id })); - } - - [Test] - public void Convert_From_Standard_Xml() - { - var nodeId = 2112; - - var xml = XElement.Parse(@" - - 115 - 268 - 10726 - jpg - - - 115 - 268 - 10726 - jpg - - "); - var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); - - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); - - var nav = node.CreateNavigator(); - - var converted = publishedMedia.CreateFromCacheValues( - publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/Image"), nodeId)); - - Assert.AreEqual(nodeId, converted.Id); - Assert.AreEqual(3, converted.Level); - Assert.AreEqual(1, converted.SortOrder); - Assert.AreEqual("Sam's Umbraco Image", converted.Name); - Assert.AreEqual("-1,1111,2222,2112", converted.Path); - } - - [Test] - public void Detects_Error_In_Xml() - { - var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); - var nav = errorXml.CreateNavigator(); - - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); - var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); - - Assert.IsNull(converted); - } - } -} +//using System.Web; +//using System.Xml.Linq; +//using System.Xml.XPath; +//using NUnit.Framework; +//using Umbraco.Core; +//using Umbraco.Core.Models; +//using Umbraco.Tests.TestHelpers; +//using Umbraco.Tests.TestHelpers.Entities; +//using Umbraco.Tests.UmbracoExamine; +//using Umbraco.Web; +//using Umbraco.Web.PublishedCache.XmlPublishedCache; +//using System.Linq; +//using System.Threading; +//using System.Xml; +//using Examine; +//using Umbraco.Core.Cache; +//using Umbraco.Core.Models.PublishedContent; +//using Umbraco.Core.Strings; +//using Umbraco.Examine; +//using Current = Umbraco.Web.Composing.Current; +//using Umbraco.Tests.Testing; +//using Umbraco.Core.Composing; +//using Umbraco.Core.Models.Membership; +//using Umbraco.Core.PropertyEditors; +// +//namespace Umbraco.Tests.PublishedContent +//{ +// /// +// /// Tests the typed extension methods on IPublishedContent using the DefaultPublishedMediaStore +// /// +// [TestFixture] +// [Apartment(ApartmentState.STA)] +// [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] +// public class PublishedMediaTests : PublishedContentTestBase +// { +// /// +// /// sets up resolvers before resolution is frozen +// /// +// protected override void Compose() +// { +// base.Compose(); +// +// Composition.WithCollectionBuilder() +// .Clear() +// .Append(); +// } +// +// private IMediaType MakeNewMediaType(IUser user, string text, int parentId = -1) +// { +// var mt = new MediaType(parentId) { Name = text, Alias = text, Thumbnail = "icon-folder", Icon = "icon-folder" }; +// ServiceContext.MediaTypeService.Save(mt); +// return mt; +// } +// +// private IMedia MakeNewMedia(string name, IMediaType mediaType, IUser user, int parentId) +// { +// var m = ServiceContext.MediaService.CreateMediaWithIdentity(name, parentId, mediaType.Alias); +// return m; +// } +// +// /// +// /// Shared with PublishMediaStoreTests +// /// +// /// +// /// +// /// +// internal IPublishedContent GetNode(int id, UmbracoContext umbracoContext) +// { +// var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new StaticCacheProvider(), ContentTypesCache); +// var doc = cache.GetById(id); +// Assert.IsNotNull(doc); +// return doc; +// } +// +// private IPublishedContent GetNode(int id) +// { +// return GetNode(id, GetUmbracoContext("/test")); +// } +// +// [Test] +// public void Get_Property_Value_Uses_Converter() +// { +// var mType = MockedContentTypes.CreateImageMediaType("image2"); +// //lets add an RTE to this +// mType.PropertyGroups.First().PropertyTypes.Add( +// new PropertyType("test", ValueStorageType.Nvarchar, "content") +// { +// Name = "Rich Text", +// DataTypeId = -87 //tiny mce +// }); +// ServiceContext.MediaTypeService.Save(mType); +// var media = MockedMedia.CreateMediaImage(mType, -1); +// media.Properties["content"].SetValue("
This is some content
"); +// ServiceContext.MediaService.Save(media); +// +// var publishedMedia = GetNode(media.Id); +// +// var propVal = publishedMedia.Value("content"); +// Assert.IsInstanceOf(propVal); +// Assert.AreEqual("
This is some content
", propVal.ToString()); +// +// var propVal2 = publishedMedia.Value("content"); +// Assert.IsInstanceOf(propVal2); +// Assert.AreEqual("
This is some content
", propVal2.ToString()); +// +// var propVal3 = publishedMedia.Value("Content"); +// Assert.IsInstanceOf(propVal3); +// Assert.AreEqual("
This is some content
", propVal3.ToString()); +// } +// +// [Test] +// public void Ensure_Children_Sorted_With_Examine() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// validator: new ContentValueSetValidator(true))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// var searcher = indexer.GetSearcher(); +// var ctx = GetUmbracoContext("/test"); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace +// var publishedMedia = cache.GetById(1111); +// var rootChildren = publishedMedia.Children().ToArray(); +// var currSort = 0; +// for (var i = 0; i < rootChildren.Count(); i++) +// { +// Assert.GreaterOrEqual(rootChildren[i].SortOrder, currSort); +// currSort = rootChildren[i].SortOrder; +// } +// } +// } +// +// [Test] +// public void Do_Not_Find_In_Recycle_Bin() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// //include unpublished content since this uses the 'internal' indexer, it's up to the media cache to filter +// validator: new ContentValueSetValidator(false))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// var searcher = indexer.GetSearcher(); +// var ctx = GetUmbracoContext("/test"); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //ensure it is found +// var publishedMedia = cache.GetById(3113); +// Assert.IsNotNull(publishedMedia); +// +// //move item to recycle bin +// var newXml = XElement.Parse(@" +// +// 115 +// 268 +// 10726 +// jpg +// "); +// indexer.IndexItems(new[]{ newXml.ConvertToValueSet("media") }); +// +// +// //ensure it still exists in the index (raw examine search) +// var criteria = searcher.CreateQuery(); +// var filter = criteria.Id(3113); +// var found = filter.Execute(); +// Assert.IsNotNull(found); +// Assert.AreEqual(1, found.TotalItemCount); +// +// //ensure it does not show up in the published media store +// var recycledMedia = cache.GetById(3113); +// Assert.IsNull(recycledMedia); +// +// } +// +// } +// +// [Test] +// public void Children_With_Examine() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// validator: new ContentValueSetValidator(true))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// var searcher = indexer.GetSearcher(); +// var ctx = GetUmbracoContext("/test"); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace +// var publishedMedia = cache.GetById(1111); +// var rootChildren = publishedMedia.Children(); +// Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { 2222, 1113, 1114, 1115, 1116 })); +// +// var publishedChild1 = cache.GetById(2222); +// var subChildren = publishedChild1.Children(); +// Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { 2112 })); +// } +// } +// +// [Test] +// public void Descendants_With_Examine() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// validator: new ContentValueSetValidator(true))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// var searcher = indexer.GetSearcher(); +// var ctx = GetUmbracoContext("/test"); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace +// var publishedMedia = cache.GetById(1111); +// var rootDescendants = publishedMedia.Descendants(); +// Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1113, 1114, 1115, 1116 })); +// +// var publishedChild1 = cache.GetById(2222); +// var subDescendants = publishedChild1.Descendants(); +// Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 3113 })); +// } +// } +// +// [Test] +// public void DescendantsOrSelf_With_Examine() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// validator: new ContentValueSetValidator(true))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// var searcher = indexer.GetSearcher(); +// var ctx = GetUmbracoContext("/test"); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace +// var publishedMedia = cache.GetById(1111); +// var rootDescendants = publishedMedia.DescendantsOrSelf(); +// Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 1111, 2112, 2222, 1113, 1114, 1115, 1116 })); +// +// var publishedChild1 = cache.GetById(2222); +// var subDescendants = publishedChild1.DescendantsOrSelf(); +// Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2222, 2112, 3113 })); +// } +// } +// +// [Test] +// public void Ancestors_With_Examine() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// validator: new ContentValueSetValidator(true))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// var ctx = GetUmbracoContext("/test"); +// var searcher = indexer.GetSearcher(); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace +// var publishedMedia = cache.GetById(3113); +// var ancestors = publishedMedia.Ancestors(); +// Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1111 })); +// } +// +// } +// +// [Test] +// public void AncestorsOrSelf_With_Examine() +// { +// var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); +// +// using (var luceneDir = new RandomIdRamDirectory()) +// using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, +// validator: new ContentValueSetValidator(true))) +// using (indexer.ProcessNonAsync()) +// { +// rebuilder.RegisterIndex(indexer.Name); +// rebuilder.Populate(indexer); +// +// +// var ctx = GetUmbracoContext("/test"); +// var searcher = indexer.GetSearcher(); +// var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, indexer, new StaticCacheProvider(), ContentTypesCache); +// +// //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace +// var publishedMedia = cache.GetById(3113); +// var ancestors = publishedMedia.AncestorsOrSelf(); +// Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 3113, 2112, 2222, 1111 })); +// } +// } +// +// [Test] +// public void Children_Without_Examine() +// { +// var user = ServiceContext.UserService.GetUserById(0); +// var mType = MakeNewMediaType(user, "TestMediaType"); +// var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); +// +// var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); +// var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); +// var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); +// +// var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); +// var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); +// var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); +// +// var publishedMedia = GetNode(mRoot.Id); +// var rootChildren = publishedMedia.Children(); +// Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mChild2.Id, mChild3.Id })); +// +// var publishedChild1 = GetNode(mChild1.Id); +// var subChildren = publishedChild1.Children(); +// Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); +// } +// +// [Test] +// public void Descendants_Without_Examine() +// { +// var user = ServiceContext.UserService.GetUserById(0); +// var mType = MakeNewMediaType(user, "TestMediaType"); +// var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); +// +// var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); +// var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); +// var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); +// +// var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); +// var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); +// var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); +// +// var publishedMedia = GetNode(mRoot.Id); +// var rootDescendants = publishedMedia.Descendants(); +// Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mChild2.Id, mChild3.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); +// +// var publishedChild1 = GetNode(mChild1.Id); +// var subDescendants = publishedChild1.Descendants(); +// Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); +// } +// +// [Test] +// public void DescendantsOrSelf_Without_Examine() +// { +// var user = ServiceContext.UserService.GetUserById(0); +// var mType = MakeNewMediaType(user, "TestMediaType"); +// var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); +// +// var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); +// var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); +// var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); +// +// var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); +// var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); +// var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); +// +// var publishedMedia = GetNode(mRoot.Id); +// var rootDescendantsOrSelf = publishedMedia.DescendantsOrSelf(); +// Assert.IsTrue(rootDescendantsOrSelf.Select(x => x.Id).ContainsAll( +// new[] { mRoot.Id, mChild1.Id, mChild2.Id, mChild3.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); +// +// var publishedChild1 = GetNode(mChild1.Id); +// var subDescendantsOrSelf = publishedChild1.DescendantsOrSelf(); +// Assert.IsTrue(subDescendantsOrSelf.Select(x => x.Id).ContainsAll( +// new[] { mChild1.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); +// } +// +// [Test] +// public void Parent_Without_Examine() +// { +// var user = ServiceContext.UserService.GetUserById(0); +// var mType = MakeNewMediaType(user, "TestMediaType"); +// var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); +// +// var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); +// var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); +// var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); +// +// var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); +// var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); +// var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); +// +// var publishedRoot = GetNode(mRoot.Id); +// Assert.AreEqual(null, publishedRoot.Parent); +// +// var publishedChild1 = GetNode(mChild1.Id); +// Assert.AreEqual(mRoot.Id, publishedChild1.Parent.Id); +// +// var publishedSubChild1 = GetNode(mSubChild1.Id); +// Assert.AreEqual(mChild1.Id, publishedSubChild1.Parent.Id); +// } +// +// [Test] +// public void Ancestors_Without_Examine() +// { +// var user = ServiceContext.UserService.GetUserById(0); +// var mType = MakeNewMediaType(user, "TestMediaType"); +// var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); +// +// var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); +// var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); +// var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); +// +// var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); +// var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); +// var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); +// +// var publishedSubChild1 = GetNode(mSubChild1.Id); +// Assert.IsTrue(publishedSubChild1.Ancestors().Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mRoot.Id })); +// } +// +// [Test] +// public void AncestorsOrSelf_Without_Examine() +// { +// var user = ServiceContext.UserService.GetUserById(0); +// var mType = MakeNewMediaType(user, "TestMediaType"); +// var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); +// +// var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); +// var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); +// var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); +// +// var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); +// var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); +// var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); +// +// var publishedSubChild1 = GetNode(mSubChild1.Id); +// Assert.IsTrue(publishedSubChild1.AncestorsOrSelf().Select(x => x.Id).ContainsAll( +// new[] { mSubChild1.Id, mChild1.Id, mRoot.Id })); +// } +// +// [Test] +// public void Convert_From_Standard_Xml() +// { +// var nodeId = 2112; +// +// var xml = XElement.Parse(@" +// +// 115 +// 268 +// 10726 +// jpg +// +// +// 115 +// 268 +// 10726 +// jpg +// +// "); +// var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); +// +// var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); +// +// var nav = node.CreateNavigator(); +// +// var converted = publishedMedia.CreateFromCacheValues( +// publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/Image"), nodeId)); +// +// Assert.AreEqual(nodeId, converted.Id); +// Assert.AreEqual(3, converted.Level); +// Assert.AreEqual(1, converted.SortOrder); +// Assert.AreEqual("Sam's Umbraco Image", converted.Name); +// Assert.AreEqual("-1,1111,2222,2112", converted.Path); +// } +// +// [Test] +// public void Detects_Error_In_Xml() +// { +// var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); +// var nav = errorXml.CreateNavigator(); +// +// var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache); +// var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); +// +// Assert.IsNull(converted); +// } +// } +//} diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index d4494c5f91..21353049d8 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -864,79 +864,79 @@ namespace Umbraco.Web return content.DescendantsOrSelf(level).OfType(); } - public static IPublishedContent Descendant(this IPublishedContent content) + public static IPublishedContent Descendant(this IPublishedContent content, string culture = null) { - return content.Children.FirstOrDefault(); + return content.Children(culture).FirstOrDefault(); } - public static IPublishedContent Descendant(this IPublishedContent content, int level) + public static IPublishedContent Descendant(this IPublishedContent content, int level, string culture = null) { - return content.EnumerateDescendants(false).FirstOrDefault(x => x.Level == level); + return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level); } - public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias) + public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.EnumerateDescendants(false).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias); + return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias); } - public static T Descendant(this IPublishedContent content) + public static T Descendant(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.EnumerateDescendants(false).FirstOrDefault(x => x is T) as T; + return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x is T) as T; } - public static T Descendant(this IPublishedContent content, int level) + public static T Descendant(this IPublishedContent content, int level, string culture = null) where T : class, IPublishedContent { - return content.Descendant(level) as T; + return content.Descendant(level, culture) as T; } - public static IPublishedContent DescendantOrSelf(this IPublishedContent content) + public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string culture = null) { return content; } - public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level) + public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string culture = null) { - return content.EnumerateDescendants(true).FirstOrDefault(x => x.Level == level); + return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level); } - public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias) + public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.EnumerateDescendants(true).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias); + return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias); } - public static T DescendantOrSelf(this IPublishedContent content) + public static T DescendantOrSelf(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.EnumerateDescendants(true).FirstOrDefault(x => x is T) as T; + return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x is T) as T; } - public static T DescendantOrSelf(this IPublishedContent content, int level) + public static T DescendantOrSelf(this IPublishedContent content, int level, string culture = null) where T : class, IPublishedContent { - return content.DescendantOrSelf(level) as T; + return content.DescendantOrSelf(level, culture) as T; } - internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func func) + internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func func, string culture = null) { - return content.EnumerateDescendants(orSelf).Where(x => func == null || func(x)); + return content.EnumerateDescendants(orSelf, culture).Where(x => func == null || func(x)); } - internal static IEnumerable EnumerateDescendants(this IPublishedContent content, bool orSelf) + internal static IEnumerable EnumerateDescendants(this IPublishedContent content, bool orSelf, string culture = null) { if (content == null) throw new ArgumentNullException(nameof(content)); if (orSelf) yield return content; - foreach (var desc in content.Children.SelectMany(x => x.EnumerateDescendants())) + foreach (var desc in content.Children(culture).SelectMany(x => x.EnumerateDescendants())) yield return desc; } - internal static IEnumerable EnumerateDescendants(this IPublishedContent content) + internal static IEnumerable EnumerateDescendants(this IPublishedContent content, string culture = null) { yield return content; - foreach (var desc in content.Children.SelectMany(x => x.EnumerateDescendants())) + foreach (var desc in content.Children(culture).SelectMany(x => x.EnumerateDescendants())) yield return desc; } @@ -1022,6 +1022,23 @@ namespace Umbraco.Web #region Axes: children + + private static IEnumerable WhereHasCulture(this IEnumerable contents, string culture = null) + { + if (contents == null) throw new ArgumentNullException(nameof(contents)); + + var actualCulture = culture ?? GetCurrentCulture(); + + return contents.Where(x=>x.HasCulture(actualCulture) ||x.HasCulture(null)); + } + + private static string GetCurrentCulture() + { + + //Review: is this the correct way to get the current culture? + return System.Threading.Thread.CurrentThread.CurrentUICulture.Name; + } + /// /// Gets the children of the content. /// @@ -1031,10 +1048,10 @@ namespace Umbraco.Web /// Children are sorted by their sortOrder. /// This method exists for consistency, it is the same as calling content.Children as a property. /// - public static IEnumerable Children(this IPublishedContent content) + public static IEnumerable Children(this IPublishedContent content, string culture = null) { if (content == null) throw new ArgumentNullException(nameof(content)); - return content.Children; + return content.Children.WhereHasCulture(culture); } /// @@ -1046,9 +1063,9 @@ namespace Umbraco.Web /// /// Children are sorted by their sortOrder. /// - public static IEnumerable Children(this IPublishedContent content, Func predicate) + public static IEnumerable Children(this IPublishedContent content, Func predicate, string culture = null) { - return content.Children().Where(predicate); + return content.Children(culture).Where(predicate); } /// @@ -1057,9 +1074,9 @@ namespace Umbraco.Web /// The content. /// One or more content type alias. /// The children of the content, of any of the specified types. - public static IEnumerable Children(this IPublishedContent content, params string[] alias) + public static IEnumerable Children(this IPublishedContent content, string culture = null, params string[] alias) { - return content.Children(x => alias.InvariantContains(x.ContentType.Alias)); + return content.Children(x => alias.InvariantContains(x.ContentType.Alias), culture); } /// @@ -1071,15 +1088,15 @@ namespace Umbraco.Web /// /// Children are sorted by their sortOrder. /// - public static IEnumerable Children(this IPublishedContent content) + public static IEnumerable Children(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.Children().OfType(); + return content.Children(culture).OfType(); } - public static IPublishedContent FirstChild(this IPublishedContent content) + public static IPublishedContent FirstChild(this IPublishedContent content, string culture = null) { - return content.Children().FirstOrDefault(); + return content.Children(culture).FirstOrDefault(); } /// @@ -1088,26 +1105,26 @@ namespace Umbraco.Web /// The content. /// The content type alias. /// The first child of content, of the given content type. - public static IPublishedContent FirstChild(this IPublishedContent content, string alias) + public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture = null) { - return content.Children(alias).FirstOrDefault(); + return content.Children(culture,alias).FirstOrDefault(); } - public static IPublishedContent FirstChild(this IPublishedContent content, Func predicate) + public static IPublishedContent FirstChild(this IPublishedContent content, Func predicate, string culture = null) { - return content.Children(predicate).FirstOrDefault(); + return content.Children(predicate, culture).FirstOrDefault(); } - public static T FirstChild(this IPublishedContent content) + public static T FirstChild(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.Children().FirstOrDefault(); + return content.Children(culture).FirstOrDefault(); } - public static T FirstChild(this IPublishedContent content, Func predicate) + public static T FirstChild(this IPublishedContent content, Func predicate, string culture = null) where T : class, IPublishedContent { - return content.Children().FirstOrDefault(predicate); + return content.Children(culture).FirstOrDefault(predicate); } /// @@ -1117,9 +1134,9 @@ namespace Umbraco.Web /// A service context. /// An optional content type alias. /// The children of the content. - public static DataTable ChildrenAsTable(this IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "") + public static DataTable ChildrenAsTable(this IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null) { - return GenerateDataTable(content, services, contentTypeAliasFilter); + return GenerateDataTable(content, services, contentTypeAliasFilter, culture); } /// @@ -1129,13 +1146,13 @@ namespace Umbraco.Web /// A service context. /// An optional content type alias. /// The children of the content. - private static DataTable GenerateDataTable(IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "") + private static DataTable GenerateDataTable(IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null) { var firstNode = contentTypeAliasFilter.IsNullOrWhiteSpace() - ? content.Children.Any() - ? content.Children.ElementAt(0) + ? content.Children(culture).Any() + ? content.Children(culture).ElementAt(0) : null - : content.Children.FirstOrDefault(x => x.ContentType.Alias == contentTypeAliasFilter); + : content.Children(culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAliasFilter); if (firstNode == null) return new DataTable(); //no children found From 20d6a3b4b496dfd61ca2e10b35faa5daa46d6eb3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 01:02:21 +1100 Subject: [PATCH 104/223] some cleanup and ensure the package file is deleted after install --- src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs | 2 +- src/Umbraco.Web/Editors/PackageInstallController.cs | 4 +--- src/Umbraco.Web/Models/PackageInstallModel.cs | 5 ----- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 4695ccb673..3dee5686ff 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -50,7 +50,7 @@ namespace Umbraco.Core.Packaging Url = package.Element("url")?.Value, IconUrl = package.Element("iconUrl")?.Value, UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), - UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type")), + UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type"), true), Control = package.Element("control")?.Value, Actions = xml.Root.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value Files = xml.Root.Element("files")?.Elements("file")?.Select(CompiledPackageFile.Create).ToList() ?? new List(), diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 38b75a27f8..2dfb5e12e4 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -287,7 +287,6 @@ namespace Umbraco.Web.Editors var model = new LocalPackageInstallModel { PackageGuid = Guid.Parse(packageGuid), - //RepositoryGuid = Guid.Parse("65194810-1f85-11dd-bd0b-0800200c9a66"), ZipFileName = fileName }; @@ -415,7 +414,7 @@ namespace Umbraco.Web.Editors var clientDependencyUpdated = clientDependencyConfig.UpdateVersionNumber( UmbracoVersion.SemanticVersion, DateTime.UtcNow, "yyyyMMdd"); - //fixme: when do we delete the zip file? + zipFile.Delete(); var redirectUrl = ""; if (packageInfo.Control.IsNullOrWhiteSpace() == false) @@ -431,7 +430,6 @@ namespace Umbraco.Web.Editors Id = model.Id, ZipFileName = model.ZipFileName, PackageGuid = model.PackageGuid, - //RepositoryGuid = model.RepositoryGuid, PostInstallationPath = redirectUrl }; diff --git a/src/Umbraco.Web/Models/PackageInstallModel.cs b/src/Umbraco.Web/Models/PackageInstallModel.cs index 2decaeb098..1ec7ddd434 100644 --- a/src/Umbraco.Web/Models/PackageInstallModel.cs +++ b/src/Umbraco.Web/Models/PackageInstallModel.cs @@ -15,11 +15,6 @@ namespace Umbraco.Web.Models [DataMember(Name = "packageGuid")] public Guid PackageGuid { get; set; } - ////TODO: Do we need this? - //[DataMember(Name = "repositoryGuid")] - //public Guid RepositoryGuid { get; set; } - - [DataMember(Name = "zipFileName")] public string ZipFileName { get; set; } From 5995a7ec843e5ca50d36a98eb4f7fd0de03e4cb4 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 15:05:04 +0100 Subject: [PATCH 105/223] a small change to let Git see changes --- src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 9ec970f1fe..51935e6517 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -123,6 +123,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}"); To("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}"); + //FINAL From 2e782a4f114c44184f5076a07fbe3c94b5104524 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 15 Jan 2019 15:10:50 +0100 Subject: [PATCH 106/223] Mapping IsContainer into AdditionalData using IEntitySlim to EntityBasic mapper --- src/Umbraco.Web/Editors/EntityController.cs | 2 +- src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 993489855f..500b25ab2e 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -769,7 +769,7 @@ namespace Umbraco.Web.Editors { throw new HttpResponseException(HttpStatusCode.NotFound); } - return Mapper.Map(found); + return Mapper.Map(found); } //now we need to convert the unknown ones switch (entityType) diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs index 178027857c..ff7fcfc0b0 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.Models.Mapping { internal class EntityMapperProfile : Profile { - private static string GetContentTypeIcon(EntitySlim entity) + private static string GetContentTypeIcon(IEntitySlim entity) => entity is ContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null; public EntityMapperProfile() @@ -24,7 +24,7 @@ namespace Umbraco.Web.Models.Mapping // create, capture, cache var contentTypeUdiResolver = new ContentTypeUdiResolver(); - CreateMap() + CreateMap() .ForMember(dest => dest.Name, opt => opt.ResolveUsing()) .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(ObjectTypes.GetUdiType(src.NodeObjectType), src.Key))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => GetContentTypeIcon(src))) @@ -36,6 +36,8 @@ namespace Umbraco.Web.Models.Mapping { dest.Icon = "icon-user"; } + + dest.AdditionalData.Add("IsContainer", src.IsContainer); }); CreateMap() @@ -186,9 +188,9 @@ namespace Umbraco.Web.Models.Mapping /// /// Resolves the name for a content item/content variant /// - private class NameResolver : IValueResolver + private class NameResolver : IValueResolver { - public string Resolve(EntitySlim source, EntityBasic destination, string destMember, ResolutionContext context) + public string Resolve(IEntitySlim source, EntityBasic destination, string destMember, ResolutionContext context) { if (!(source is DocumentEntitySlim doc)) return source.Name; From 11ffafacdf42a461b793df8a3e32fda1c88b6a4f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 15:12:59 +0100 Subject: [PATCH 107/223] Revert "Revert "Identify element types"" This reverts commit ff6a9ba9 --- .../Migrations/Upgrade/UmbracoPlan.cs | 1 + .../V_8_0_0/AddContentTypeIsElementColumn.cs | 15 ++++++++++ src/Umbraco.Core/Models/ContentTypeBase.cs | 10 +++++++ .../Models/ContentTypeBaseExtensions.cs | 3 +- src/Umbraco.Core/Models/IContentTypeBase.cs | 12 +++++++- .../PublishedContent/PublishedItemType.cs | 7 ++++- .../Persistence/Dtos/ContentTypeDto.cs | 4 +++ .../Factories/ContentTypeFactory.cs | 2 ++ .../Persistence/Mappers/ContentTypeMapper.cs | 1 + .../Persistence/Mappers/MediaTypeMapper.cs | 1 + .../Persistence/Mappers/MemberTypeMapper.cs | 1 + .../Implement/ContentTypeRepositoryBase.cs | 6 ++-- .../Services/EntityXmlSerializer.cs | 3 +- .../Services/Implement/PackagingService.cs | 4 +++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../PublishedContent/PublishedContentTests.cs | 1 - .../Services/ContentTypeServiceTests.cs | 30 +++++++++++++++++++ .../ContentEditing/ContentItemDisplay.cs | 8 ++++- .../Models/Mapping/ContentMapperProfile.cs | 5 ++-- 19 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index b469c02a3c..9ec970f1fe 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -121,6 +121,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{648A2D5F-7467-48F8-B309-E99CEEE00E2A}"); // fixed version To("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}"); To("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}"); + To("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}"); //FINAL diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs new file mode 100644 index 0000000000..1df11a3e99 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentTypeIsElementColumn.cs @@ -0,0 +1,15 @@ +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class AddContentTypeIsElementColumn : MigrationBase + { + public AddContentTypeIsElementColumn(IMigrationContext context) : base(context) + { } + + public override void Migrate() + { + AddColumn("isElement"); + } + } +} diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 88b1179f6d..b6ea9f50a0 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -26,6 +26,7 @@ namespace Umbraco.Core.Models private string _thumbnail = "folder.png"; private bool _allowedAsRoot; // note: only one that's not 'pure element type' private bool _isContainer; + private bool _isElement; private PropertyGroupCollection _propertyGroups; private PropertyTypeCollection _noGroupPropertyTypes; private IEnumerable _allowedContentTypes; @@ -90,6 +91,7 @@ namespace Umbraco.Core.Models public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon); public readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.Thumbnail); public readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot); + public readonly PropertyInfo IsElementSelector = ExpressionHelper.GetPropertyInfo(x => x.IsElement); public readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer); public readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes); public readonly PropertyInfo PropertyGroupsSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups); @@ -180,6 +182,14 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _isContainer, Ps.Value.IsContainerSelector); } + /// + [DataMember] + public bool IsElement + { + get => _isElement; + set => SetPropertyValueAndDetectChanges(value, ref _isElement, Ps.Value.IsElementSelector); + } + /// /// Gets or sets a list of integer Ids for allowed ContentTypes /// diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs index 8af48bb881..adbc3de54f 100644 --- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs @@ -15,7 +15,8 @@ namespace Umbraco.Core.Models { var type = contentType.GetType(); var itemType = PublishedItemType.Unknown; - if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content; + if (contentType.IsElement) itemType = PublishedItemType.Element; + else if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content; else if (typeof(IMediaType).IsAssignableFrom(type)) itemType = PublishedItemType.Media; else if (typeof(IMemberType).IsAssignableFrom(type)) itemType = PublishedItemType.Member; return itemType; diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index a1d4aee02f..787e347b37 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Models /// the icon (eg. icon-home) along with an optional CSS class name representing the /// color (eg. icon-blue). Put together, the value for this scenario would be /// icon-home color-blue. - /// + /// /// If a class name for the color isn't specified, the icon color will default to black. /// string Icon { get; set; } @@ -48,6 +48,16 @@ namespace Umbraco.Core.Models /// bool IsContainer { get; set; } + /// + /// Gets or sets a value indicating whether this content type is for an element. + /// + /// + /// By default a content type is for a true media, member or document, but + /// it can also be for an element, ie a subset that can for instance be used in + /// nested content. + /// + bool IsElement { get; set; } + /// /// Gets or sets the content variation of the content type. /// diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs index e55fe66945..42e9c9538d 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedItemType.cs @@ -4,13 +4,18 @@ /// The type of published element. /// /// Can be a simple element, or a document, a media, a member. - public enum PublishedItemType // fixme - need to rename to PublishedElementType but then conflicts? + public enum PublishedItemType { /// /// Unknown. /// Unknown = 0, + /// + /// An element. + /// + Element, + /// /// A document. /// diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs index d930abc54c..4f3a67aa91 100644 --- a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs @@ -41,6 +41,10 @@ namespace Umbraco.Core.Persistence.Dtos [Constraint(Default = "0")] public bool IsContainer { get; set; } + [Column("isElement")] + [Constraint(Default = "0")] + public bool IsElement { get; set; } + [Column("allowAtRoot")] [Constraint(Default = "0")] public bool AllowAtRoot { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs index 38a1aa2aab..7a04a6d0d9 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs @@ -107,6 +107,7 @@ namespace Umbraco.Core.Persistence.Factories entity.CreatorId = dto.NodeDto.UserId ?? Constants.Security.UnknownUserId; entity.AllowedAsRoot = dto.AllowAtRoot; entity.IsContainer = dto.IsContainer; + entity.IsElement = dto.IsElement; entity.Trashed = dto.NodeDto.Trashed; entity.Variations = (ContentVariation) dto.Variations; } @@ -132,6 +133,7 @@ namespace Umbraco.Core.Persistence.Factories NodeId = entity.Id, AllowAtRoot = entity.AllowedAsRoot, IsContainer = entity.IsContainer, + IsElement = entity.IsElement, Variations = (byte) entity.Variations, NodeDto = BuildNodeDto(entity, nodeObjectType) }; diff --git a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs index c692a75474..a24963bace 100644 --- a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs @@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs index 3f5a6e24bc..6cf83bc7aa 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs @@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs index 28dc19171f..9a4e4ec040 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs @@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 662254d1ee..683df047f8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1283,7 +1283,7 @@ AND umbracoNode.id <> @id", if (db == null) throw new ArgumentNullException(nameof(db)); var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations, - cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey, umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, @@ -1384,6 +1384,7 @@ AND umbracoNode.id <> @id", Description = currCt.ctDesc, Icon = currCt.ctIcon, IsContainer = currCt.ctIsContainer, + IsElement = currCt.ctIsElement, NodeId = currCt.ctId, PrimaryKey = currCt.ctPk, Thumbnail = currCt.ctThumb, @@ -1422,7 +1423,7 @@ AND umbracoNode.id <> @id", var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId, cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations, - cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey, umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, @@ -1559,6 +1560,7 @@ AND umbracoNode.id <> @id", Description = currCt.ctDesc, Icon = currCt.ctIcon, IsContainer = currCt.ctIsContainer, + IsElement = currCt.ctIsElement, NodeId = currCt.ctId, PrimaryKey = currCt.ctPk, Thumbnail = currCt.ctThumb, diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index d938e032a8..38d5471bb7 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -337,7 +337,8 @@ namespace Umbraco.Core.Services new XElement("Thumbnail", contentType.Thumbnail), new XElement("Description", contentType.Description), new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()), - new XElement("IsListView", contentType.IsContainer.ToString())); + new XElement("IsListView", contentType.IsContainer.ToString()), + new XElement("IsElement", contentType.IsElement.ToString())); var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId); if(masterContentType != null) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 106d2b9f12..8f6c287cf1 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -578,6 +578,10 @@ namespace Umbraco.Core.Services.Implement if (isListView != null) contentType.IsContainer = isListView.Value.InvariantEquals("true"); + var isElement = infoElement.Element("IsElement"); + if (isListView != null) + contentType.IsElement = isElement.Value.InvariantEquals("true"); + //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set var masterElement = infoElement.Element("Master"); if (masterElement != null) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 609befd233..7d65a46f49 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -377,6 +377,7 @@ + diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 914956dce1..ab65ac82b1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -233,7 +233,6 @@ namespace Umbraco.Tests.PublishedContent } [Test] - [Ignore("Fails as long as PublishedContentModel is internal.")] // fixme public void Is_Last_From_Where_Filter2() { var doc = GetNode(1173); diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index b1a8fa26a8..8dc8a2b45c 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -22,6 +22,36 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] public class ContentTypeServiceTests : TestWithSomeContentBase { + [Test] + public void CanSaveAndGetIsElement() + { + //create content type with a property type that varies by culture + IContentType contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Nothing; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Nothing + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + ServiceContext.ContentTypeService.Save(contentType); + + contentType = ServiceContext.ContentTypeService.Get(contentType.Id); + Assert.IsFalse(contentType.IsElement); + + contentType.IsElement = true; + ServiceContext.ContentTypeService.Save(contentType); + + contentType = ServiceContext.ContentTypeService.Get(contentType.Id); + Assert.IsTrue(contentType.IsElement); + } + [Test] public void Change_Content_Type_Variation_Clears_Redirects() { diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index 4908025351..80358bfc7a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -86,6 +86,12 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } + /// + /// Indicates if the content is configured as an element + /// + [DataMember(Name = "isElement")] + public bool IsElement { get; set; } + /// /// Property indicating if this item is part of a list view parent /// @@ -117,7 +123,7 @@ namespace Umbraco.Web.Models.ContentEditing /// [DataMember(Name = "updateDate")] public DateTime UpdateDate { get; set; } - + [DataMember(Name = "template")] public string TemplateAlias { get; set; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs index 6de3bdc02c..1caf81a1eb 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs @@ -46,6 +46,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name)) .ForMember(dest => dest.IsContainer, opt => opt.MapFrom(src => src.ContentType.IsContainer)) + .ForMember(dest => dest.IsElement, opt => opt.MapFrom(src => src.ContentType.IsElement)) .ForMember(dest => dest.IsBlueprint, opt => opt.MapFrom(src => src.Blueprint)) .ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) @@ -59,7 +60,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.AllowedTemplates, opt => opt.MapFrom(content => content.ContentType.AllowedTemplates .Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false) - .ToDictionary(t => t.Alias, t => t.Name))) + .ToDictionary(t => t.Alias, t => t.Name))) .ForMember(dest => dest.AllowedActions, opt => opt.ResolveUsing(src => actionButtonsResolver.Resolve(src))) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); @@ -140,5 +141,5 @@ namespace Umbraco.Web.Models.Mapping return source.CultureInfos.TryGetValue(culture, out var name) && !name.Name.IsNullOrWhiteSpace() ? name.Name : $"(({source.Name}))"; } } - } + } } From 0b9705ca3f44b73bb3cc7e9d2386a979abe9a5da Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jan 2019 15:13:10 +0100 Subject: [PATCH 108/223] Revert "Revert "Support IContentType.IsElement"" This reverts commit a5efc25c --- .../services/umbdataformatter.service.js | 18 +++++++-------- .../permissions/permissions.controller.js | 22 +++++++------------ .../views/permissions/permissions.html | 20 +++++++++++++++-- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 ++ .../Umbraco/config/lang/en_us.xml | 2 ++ .../ContentTypeCompositionDisplay.cs | 4 ++++ .../Models/ContentEditing/ContentTypeSave.cs | 3 +++ 7 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index e31742e660..1e6fc5d643 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -64,7 +64,7 @@ var saveModel = _.pick(displayModel, 'compositeContentTypes', 'isContainer', 'allowAsRoot', 'allowedTemplates', 'allowedContentTypes', 'alias', 'description', 'thumbnail', 'name', 'id', 'icon', 'trashed', - 'key', 'parentId', 'alias', 'path', 'allowCultureVariant'); + 'key', 'parentId', 'alias', 'path', 'allowCultureVariant', 'isElement'); //TODO: Map these saveModel.allowedTemplates = _.map(displayModel.allowedTemplates, function (t) { return t.alias; }); @@ -262,7 +262,7 @@ saveModel[props[m]] = startId.id; } - saveModel.parentId = -1; + saveModel.parentId = -1; return saveModel; }, @@ -293,7 +293,7 @@ }); saveModel.email = propEmail.value.trim(); saveModel.username = propLogin.value.trim(); - + saveModel.password = this.formatChangePasswordModel(propPass.value); var selectedGroups = []; @@ -336,7 +336,7 @@ /** formats the display model used to display the media to the model used to save the media */ formatMediaPostData: function (displayModel, action) { - //NOTE: the display model inherits from the save model so we can in theory just post up the display model but + //NOTE: the display model inherits from the save model so we can in theory just post up the display model but // we don't want to post all of the data as it is unecessary. var saveModel = { id: displayModel.id, @@ -354,7 +354,7 @@ /** formats the display model used to display the content to the model used to save the content */ formatContentPostData: function (displayModel, action) { - //NOTE: the display model inherits from the save model so we can in theory just post up the display model but + //NOTE: the display model inherits from the save model so we can in theory just post up the display model but // we don't want to post all of the data as it is unecessary. var saveModel = { id: displayModel.id, @@ -379,7 +379,7 @@ var propExpireDate = displayModel.removeDate; var propReleaseDate = displayModel.releaseDate; var propTemplate = displayModel.template; - + saveModel.expireDate = propExpireDate ? propExpireDate : null; saveModel.releaseDate = propReleaseDate ? propReleaseDate : null; saveModel.templateAlias = propTemplate ? propTemplate : null; @@ -389,8 +389,8 @@ /** * This formats the server GET response for a content display item - * @param {} displayModel - * @returns {} + * @param {} displayModel + * @returns {} */ formatContentGetData: function(displayModel) { @@ -418,7 +418,7 @@ } }); }); - + //now assign this same invariant property instance to the same index of the other variants property array for (var j = 1; j < displayModel.variants.length; j++) { diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js index 4a7a870618..317fe094ae 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.controller.js @@ -25,6 +25,7 @@ vm.removeChild = removeChild; vm.toggleAllowAsRoot = toggleAllowAsRoot; vm.toggleAllowCultureVariants = toggleAllowCultureVariants; + vm.toggleIsElement = toggleIsElement; /* ---------- INIT ---------- */ @@ -84,25 +85,18 @@ $scope.model.allowedContentTypes.splice(selectedChildIndex, 1); } - /** - * Toggle the $scope.model.allowAsRoot value to either true or false - */ - function toggleAllowAsRoot(){ - if($scope.model.allowAsRoot){ - $scope.model.allowAsRoot = false; - return; - } + // note: "safe toggling" here ie handling cases where the value is undefined, etc - $scope.model.allowAsRoot = true; + function toggleAllowAsRoot() { + $scope.model.allowAsRoot = $scope.model.allowAsRoot ? false : true; } function toggleAllowCultureVariants() { - if ($scope.model.allowCultureVariant) { - $scope.model.allowCultureVariant = false; - return; - } + $scope.model.allowCultureVariant = $scope.model.allowCultureVariant ? false : true; + } - $scope.model.allowCultureVariant = true; + function toggleIsElement() { + $scope.model.isElement = $scope.model.isElement ? false : true; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html index ec1e528f8c..0d74c655d7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/views/permissions/permissions.html @@ -53,9 +53,25 @@ hotkey="alt+shift+v"> - + - +
+ +
+
+ +
+ +
+ + +
+ +
+ + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 386d3af518..987203442a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1518,6 +1518,8 @@ To manage your website, simply open the Umbraco back office and start adding con Allow varying by culture Allow editors to create content of this type in different languages Allow varying by culture + Is an Element type + An Element type is meant to be used for instance in Nested Content, and not in the tree Building models 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 5de373f571..1860d3afc9 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1559,6 +1559,8 @@ To manage your website, simply open the Umbraco back office and start adding con Allow varying by culture Allow editors to create content of this type in different languages Allow varying by culture + Is an Element type + An Element type is meant to be used for instance in Nested Content, and not in the tree Add language diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs index 7211ddbf61..e5e74c2749 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeCompositionDisplay.cs @@ -26,6 +26,10 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } + //Element + [DataMember(Name = "isElement")] + public bool IsElement { get; set; } + [DataMember(Name = "listViewEditorName")] [ReadOnly(true)] public string ListViewEditorName { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs index c2ec70d3dc..b1d24c5fd2 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeSave.cs @@ -25,6 +25,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "isContainer")] public bool IsContainer { get; set; } + [DataMember(Name = "isElement")] + public bool IsElement { get; set; } + [DataMember(Name = "allowAsRoot")] public bool AllowAsRoot { get; set; } From f9cd22d908ddfbfb09dd8ef0b6d033b1f32f18d1 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 15 Jan 2019 15:43:10 +0100 Subject: [PATCH 109/223] Added a comment explaining why we need the delay --- .../src/common/services/editor.service.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index c495c4e7a1..721efe251c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -245,7 +245,9 @@ When building a custom infinite editor view you can use the same components as a // emit event to let components know an editor has been removed eventsService.emit("appState.editors.close", args); - + + // delay required to map the properties to the correct editor due + // to another delay in the closing animation of the editor $timeout(function() { // rebind keyboard shortcuts for the new editor in focus rebindKeyboardShortcuts(); From b7c15dc393d43a40a33670b836033411ea0e0f72 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 01:53:08 +1100 Subject: [PATCH 110/223] gets readme and our package install working --- .../src/common/resources/package.resource.js | 2 +- .../views/packages/views/repo.controller.js | 162 ++++++++++-------- src/Umbraco.Web/Editors/PackageController.cs | 41 ++++- .../Editors/PackageInstallController.cs | 36 +--- .../ContentEditing/InstalledPackageModel.cs | 3 + 5 files changed, 135 insertions(+), 109 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index ce2a557390..0d74d0fdd3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -19,7 +19,7 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.get( umbRequestHelper.getApiUrl( - "packageInstallApiBaseUrl", + "packageApiBaseUrl", "GetInstalled")), 'Failed to get installed packages'); }, diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js index 395800d329..b77326d2fc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js @@ -32,6 +32,8 @@ vm.search = search; vm.installCompleted = false; + var labels = {}; + var currSort = "Latest"; //used to cancel any request in progress if another one needs to take it's place var canceler = null; @@ -52,22 +54,38 @@ vm.loading = true; + var labelKeys = [ + "packager_installStateImporting", + "packager_installStateInstalling", + "packager_installStateRestarting", + "packager_installStateComplete", + "packager_installStateCompleted" + ]; + + localizationService.localizeMany(labelKeys).then(function (values) { + labels.installStateImporting = values[0]; + labels.installStateInstalling = values[1]; + labels.installStateRestarting = values[2]; + labels.installStateComplete = values[3]; + labels.installStateCompleted = values[4]; + }); + $q.all([ - ourPackageRepositoryResource.getCategories() - .then(function(cats) { + ourPackageRepositoryResource.getCategories() + .then(function (cats) { vm.categories = cats; }), - ourPackageRepositoryResource.getPopular(8) - .then(function(pack) { + ourPackageRepositoryResource.getPopular(8) + .then(function (pack) { vm.popular = pack.packages; }), - ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, vm.pagination.pageSize, currSort) - .then(function(pack) { + ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, vm.pagination.pageSize, currSort) + .then(function (pack) { vm.packages = pack.packages; vm.pagination.totalPages = Math.ceil(pack.total / vm.pagination.pageSize); }) - ]) - .then(function() { + ]) + .then(function () { vm.loading = false; }); @@ -94,18 +112,18 @@ currSort = "Latest"; $q.all([ - ourPackageRepositoryResource.getPopular(8, searchCategory) - .then(function(pack) { + ourPackageRepositoryResource.getPopular(8, searchCategory) + .then(function (pack) { vm.popular = pack.packages; }), - ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, vm.pagination.pageSize, currSort, searchCategory, vm.searchQuery) - .then(function(pack) { + ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, vm.pagination.pageSize, currSort, searchCategory, vm.searchQuery) + .then(function (pack) { vm.packages = pack.packages; vm.pagination.totalPages = Math.ceil(pack.total / vm.pagination.pageSize); vm.pagination.pageNumber = 1; }) - ]) - .then(function() { + ]) + .then(function () { vm.loading = false; selectedCategory.active = reset === false; }); @@ -115,12 +133,12 @@ ourPackageRepositoryResource.getDetails(selectedPackage.id) .then(function (pack) { packageResource.validateInstalled(pack.name, pack.latestVersion) - .then(function() { + .then(function () { //ok, can install vm.package = pack; vm.package.isValid = true; vm.packageViewState = "packageDetails"; - }, function() { + }, function () { //nope, cannot install vm.package = pack; vm.package.isValid = false; @@ -130,7 +148,7 @@ } function setPackageViewState(state) { - if(state) { + if (state) { vm.packageViewState = state; } } @@ -164,13 +182,13 @@ packageResource .fetch(selectedPackage.id) - .then(function(pack) { - vm.packageViewState = "packageInstall"; - vm.loading = false; - vm.localPackage = pack; - vm.localPackage.allowed = true; + .then(function (pack) { + vm.packageViewState = "packageInstall"; + vm.loading = false; + vm.localPackage = pack; + vm.localPackage.allowed = true; }, function (evt, status, headers, config) { - + if (status == 400) { //it's a validation error vm.installState.type = "error"; @@ -186,68 +204,68 @@ function installPackage(selectedPackage) { - vm.installState.status = localizationService.localize("packager_installStateImporting"); + vm.installState.status = labels.installStateImporting; vm.installState.progress = "0"; packageResource .import(selectedPackage) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateInstalling"); - vm.installState.progress = "25"; - return packageResource.installFiles(pack); - }, + .then(function (pack) { + vm.installState.status = labels.installStateInstalling; + vm.installState.progress = "25"; + return packageResource.installFiles(pack); + }, error) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateRestarting"); - vm.installState.progress = "50"; - var deferred = $q.defer(); + .then(function (pack) { + vm.installState.status = labels.installStateRestarting; + vm.installState.progress = "50"; + var deferred = $q.defer(); - //check if the app domain is restarted ever 2 seconds - var count = 0; - function checkRestart() { - $timeout(function () { + //check if the app domain is restarted ever 2 seconds + var count = 0; + function checkRestart() { + $timeout(function () { packageResource.checkRestart(pack).then(function (d) { count++; //if there is an id it means it's not restarted yet but we'll limit it to only check 10 times if (d.isRestarting && count < 10) { - checkRestart(); + checkRestart(); } else { - //it's restarted! - deferred.resolve(d); + //it's restarted! + deferred.resolve(d); } - }, - error); - }, 2000); - } + }, + error); + }, 2000); + } - checkRestart(); - - return deferred.promise; - }, error) + checkRestart(); + + return deferred.promise; + }, error) .then(function (pack) { - vm.installState.status = localizationService.localize("packager_installStateRestarting"); - vm.installState.progress = "75"; - return packageResource.installData(pack); - }, + vm.installState.status = labels.installStateInstalling; + vm.installState.progress = "75"; + return packageResource.installData(pack); + }, error) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateComplete"); - vm.installState.progress = "100"; - return packageResource.cleanUp(pack); - }, + .then(function (pack) { + vm.installState.status = labels.installStateComplete; + vm.installState.progress = "100"; + return packageResource.cleanUp(pack); + }, error) - .then(function(result) { + .then(function (result) { - if (result.postInstallationPath) { - //Put the redirect Uri in a cookie so we can use after reloading - localStorageService.set("packageInstallUri", result.postInstallationPath); - } + if (result.postInstallationPath) { + //Put the redirect Uri in a cookie so we can use after reloading + localStorageService.set("packageInstallUri", result.postInstallationPath); + } - vm.installState.status = localizationService.localize("packager_installStateCompleted"); - vm.installCompleted = true; + vm.installState.status = labels.installStateCompleted; + vm.installCompleted = true; - }, + }, error); } @@ -265,7 +283,7 @@ } - var searchDebounced = _.debounce(function(e) { + var searchDebounced = _.debounce(function (e) { $scope.$apply(function () { @@ -281,12 +299,12 @@ currSort = vm.searchQuery ? "Default" : "Latest"; ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, - vm.pagination.pageSize, - currSort, - "", - vm.searchQuery, - canceler) - .then(function(pack) { + vm.pagination.pageSize, + currSort, + "", + vm.searchQuery, + canceler) + .then(function (pack) { vm.packages = pack.packages; vm.pagination.totalPages = Math.ceil(pack.total / vm.pagination.pageSize); vm.pagination.pageNumber = 1; diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 063dcf483e..2d1d124a2c 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -1,11 +1,14 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Web.Http; using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; @@ -111,5 +114,41 @@ namespace Umbraco.Web.Editors return response; } + /// + /// Returns all installed packages - only shows their latest versions + /// + /// + public IEnumerable GetInstalled() + { + return Services.PackagingService.GetAllInstalledPackages() + .GroupBy( + //group by name + x => x.Name, + //select the package with a parsed version + pck => Version.TryParse(pck.Version, out var pckVersion) + ? new { package = pck, version = pckVersion } + : new { package = pck, version = new Version(0, 0, 0) }) + .Select(grouping => + { + //get the max version for the package + var maxVersion = grouping.Max(x => x.version); + //only return the first package with this version + return grouping.First(x => x.version == maxVersion).package; + }) + .Select(pack => new InstalledPackageModel + { + Name = pack.Name, + Id = pack.Id, + Author = pack.Author, + Version = pack.Version, + Url = pack.Url, + License = pack.License, + LicenseUrl = pack.LicenseUrl, + Files = pack.Files, + IconUrl = pack.IconUrl, + Readme = pack.Readme + }) + .ToList(); + } } } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 2dfb5e12e4..bc6db1b552 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -92,41 +92,7 @@ namespace Umbraco.Web.Editors return Ok(); } - /// - /// Returns all installed packages - only shows their latest versions - /// - /// - public IEnumerable GetInstalled() - { - return Services.PackagingService.GetAllInstalledPackages() - .GroupBy( - //group by name - x => x.Name, - //select the package with a parsed version - pck => Version.TryParse(pck.Version, out var pckVersion) - ? new { package = pck, version = pckVersion } - : new { package = pck, version = new Version(0, 0, 0) }) - .Select(grouping => - { - //get the max version for the package - var maxVersion = grouping.Max(x => x.version); - //only return the first package with this version - return grouping.First(x => x.version == maxVersion).package; - }) - .Select(pack => new InstalledPackageModel - { - Name = pack.Name, - Id = pack.Id, - Author = pack.Author, - Version = pack.Version, - Url = pack.Url, - License = pack.License, - LicenseUrl = pack.LicenseUrl, - Files = pack.Files, - IconUrl = pack.IconUrl - }) - .ToList(); - } + private void PopulateFromPackageData(LocalPackageInstallModel model) { diff --git a/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs b/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs index 9161f972bd..67bfe6fe53 100644 --- a/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs +++ b/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs @@ -32,5 +32,8 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "iconUrl")] public string IconUrl { get; set; } + + [DataMember(Name = "readme")] + public string Readme { get; set; } } } From d97b100bab5ff66b2bc0f99a7ceaf89a8e2c22ce Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 02:18:02 +1100 Subject: [PATCH 111/223] fixes merge --- src/Umbraco.Core/Packaging/PackageDataInstallation.cs | 4 ++++ src/Umbraco.Core/Services/Implement/PackagingService.cs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 2212a8957d..36066b104f 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -556,6 +556,10 @@ namespace Umbraco.Core.Packaging if (isListView != null) contentType.IsContainer = isListView.Value.InvariantEquals("true"); + var isElement = infoElement.Element("IsElement"); + if (isElement != null) + contentType.IsElement = isElement.Value.InvariantEquals("true"); + //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set var masterElement = infoElement.Element("Master"); if (masterElement != null) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 55608e605e..a5c279fa21 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -43,10 +43,6 @@ namespace Umbraco.Core.Services.Implement ICreatedPackagesRepository createdPackages, IInstalledPackagesRepository installedPackages, IPackageInstallation packageInstallation) - var isElement = infoElement.Element("IsElement"); - if (isListView != null) - contentType.IsElement = isElement.Value.InvariantEquals("true"); - { _auditService = auditService; _createdPackages = createdPackages; From 00e951c3949b015c06ce3d6576734fcffb9d7dde Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 02:35:21 +1100 Subject: [PATCH 112/223] fixes installer with async --- .../Install/Controllers/InstallApiController.cs | 15 ++++++++------- .../Install/Models/InstallSetupStep.cs | 4 +--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs index a63484fb39..c8e862abcb 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using System.Web.Http; using Newtonsoft.Json.Linq; using Umbraco.Core; @@ -75,7 +76,7 @@ namespace Umbraco.Web.Install.Controllers /// /// Installs. /// - public InstallProgressResultModel PostPerformInstall(InstallInstructions installModel) + public async Task PostPerformInstall(InstallInstructions installModel) { if (installModel == null) throw new ArgumentNullException(nameof(installModel)); @@ -94,8 +95,7 @@ namespace Umbraco.Web.Install.Controllers var step = _installSteps.GetAllSteps().Single(x => x.Name == item.Name); // if this step has any instructions then extract them - JToken instruction; - installModel.Instructions.TryGetValue(item.Name, out instruction); // else null + installModel.Instructions.TryGetValue(item.Name, out var instruction); // else null // if this step doesn't require execution then continue to the next one, this is just a fail-safe check. if (StepRequiresExecution(step, instruction) == false) @@ -107,7 +107,7 @@ namespace Umbraco.Web.Install.Controllers try { - var setupData = ExecuteStep(step, instruction); + var setupData = await ExecuteStepAsync(step, instruction); // update the status InstallStatusTracker.SetComplete(installModel.InstallId, step.Name, setupData?.SavedStepData); @@ -222,7 +222,7 @@ namespace Umbraco.Web.Install.Controllers } // executes the step - internal InstallSetupResult ExecuteStep(InstallSetupStep step, JToken instruction) + internal async Task ExecuteStepAsync(InstallSetupStep step, JToken instruction) { using (_proflog.TraceDuration($"Executing installation step: '{step.Name}'.", "Step completed")) { @@ -232,8 +232,9 @@ namespace Umbraco.Web.Install.Controllers var typedStepType = genericStepType.MakeGenericType(typeArgs); try { - var method = typedStepType.GetMethods().Single(x => x.Name == "Execute"); - return (InstallSetupResult) method.Invoke(step, new[] { model }); + var method = typedStepType.GetMethods().Single(x => x.Name == "ExecuteAsync"); + var task = (Task) method.Invoke(step, new[] { model }); + return await task; } catch (Exception ex) { diff --git a/src/Umbraco.Web/Install/Models/InstallSetupStep.cs b/src/Umbraco.Web/Install/Models/InstallSetupStep.cs index 3b017368f9..fd50d7855c 100644 --- a/src/Umbraco.Web/Install/Models/InstallSetupStep.cs +++ b/src/Umbraco.Web/Install/Models/InstallSetupStep.cs @@ -82,8 +82,6 @@ namespace Umbraco.Web.Install.Models ///
[IgnoreDataMember] public abstract Type StepType { get; } - - [IgnoreDataMember] - public bool HasUIElement => View.IsNullOrWhiteSpace() == false; + } } From 1bd5127bcf6d05b2f38a0c0121ae1e399c6ae63c Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 17:27:18 +0100 Subject: [PATCH 113/223] Actually run HealthCheck notifier --- src/Umbraco.Web/Scheduling/SchedulerComponent.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web/Scheduling/SchedulerComponent.cs b/src/Umbraco.Web/Scheduling/SchedulerComponent.cs index e4bc74b7f2..cd4f5ac933 100644 --- a/src/Umbraco.Web/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Web/Scheduling/SchedulerComponent.cs @@ -149,6 +149,7 @@ namespace Umbraco.Web.Scheduling var periodInMilliseconds = healthCheckConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000; var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _runtime, logger); + _healthCheckRunner.TryAdd(task); return task; } From 477075662163857ba32cea0a4989f1ab9438f7f4 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 18:41:02 +0100 Subject: [PATCH 114/223] Bugfix ContentCacheRefresher --- src/Umbraco.Web/Cache/ContentCacheRefresher.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs index 22f1554269..b0192e9e75 100644 --- a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs @@ -44,16 +44,14 @@ namespace Umbraco.Web.Cache public override void Refresh(JsonPayload[] payloads) { - var runtimeCache = Current.ApplicationCache.RuntimeCache; - - runtimeCache.ClearCacheObjectTypes(); + CacheHelper.RuntimeCache.ClearCacheObjectTypes(); var idsRemoved = new HashSet(); + var isolatedCache = CacheHelper.IsolatedRuntimeCache.GetOrCreateCache(); foreach (var payload in payloads) { - // remove that one - runtimeCache.ClearCacheItem(RepositoryCacheKeys.GetKey(payload.Id)); + isolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(payload.Id)); _idkMap.ClearCache(payload.Id); @@ -61,7 +59,7 @@ namespace Umbraco.Web.Cache if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.RefreshBranch | TreeChangeTypes.Remove)) { var pathid = "," + payload.Id + ","; - runtimeCache.ClearCacheObjectTypes((k, v) => v.Path.Contains(pathid)); + isolatedCache.ClearCacheObjectTypes((k, v) => v.Path.Contains(pathid)); } //if the item is being completely removed, we need to refresh the domains cache if any domain was assigned to the content From eb3d3e129c8a96583155239a85efacd1b825199f Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 19:15:06 +0100 Subject: [PATCH 115/223] Bugfix package service --- src/Umbraco.Core/Services/Implement/PackagingService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 8f6c287cf1..99ee7a098b 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -579,7 +579,7 @@ namespace Umbraco.Core.Services.Implement contentType.IsContainer = isListView.Value.InvariantEquals("true"); var isElement = infoElement.Element("IsElement"); - if (isListView != null) + if (isElement != null) contentType.IsElement = isElement.Value.InvariantEquals("true"); //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set From d4edbc8e791a9d944c737e0882b973672787147a Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 15 Jan 2019 19:38:52 +0100 Subject: [PATCH 116/223] Fix tests --- .../PublishedContent/PublishedContentTests.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index ab65ac82b1..603464e18b 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -69,8 +69,9 @@ namespace Umbraco.Tests.PublishedContent factory.CreatePropertyType("testRecursive", 1), }; var compositionAliases = new[] { "MyCompositionAlias" }; - var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes); - ContentTypesCache.GetPublishedContentTypeByAlias = alias => type; + var anythingType = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes); + var homeType = new AutoPublishedContentType(0, "home", compositionAliases, propertyTypes); + ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType; } protected override TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) @@ -236,6 +237,7 @@ namespace Umbraco.Tests.PublishedContent public void Is_Last_From_Where_Filter2() { var doc = GetNode(1173); + var ct = doc.ContentType; var items = doc.Children .Select(x => x.CreateModel()) // linq, returns IEnumerable @@ -454,11 +456,11 @@ namespace Umbraco.Tests.PublishedContent { var doc = GetNode(1046); // has child nodes - var model = doc.FirstChild(x => true); // predicate + var model = doc.FirstChild(x => true); // predicate Assert.IsNotNull(model); Assert.IsTrue(model.Id == 1173); - Assert.IsInstanceOf(model); + Assert.IsInstanceOf(model); Assert.IsInstanceOf(model); doc = GetNode(1175); // does not have child nodes From 90be93d94842b84ed86358e0d812fdd50e0afc66 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 16:27:51 +1100 Subject: [PATCH 117/223] Got upgrade status showing in the ui, started implementing merging the package definitions for upgrades but have decided to have an element for each install like we currenlty have in case there are problems installing. --- .../Models/Packaging/PackageDefinition.cs | 33 ++++++++ .../Packaging/CompiledPackageXmlParser.cs | 2 +- .../Packaging/PackageInstallType.cs | 9 ++ .../Services/IPackagingService.cs | 19 +++++ .../Services/Implement/PackagingService.cs | 81 ++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../mocks/services/localization.mocks.js | 1 - .../views/packages/views/install-local.html | 31 ++++--- src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/de.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 - .../Umbraco/config/lang/en_us.xml | 2 +- src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/ja.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/pl.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/ru.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/tr.xml | 1 - src/Umbraco.Web.UI/Umbraco/config/lang/zh.xml | 1 - .../Umbraco/config/lang/zh_tw.xml | 1 - src/Umbraco.Web.UI/umbraco/config/lang/nb.xml | 1 - .../umbraco/config/lang/zh_tw.xml | 1 - .../Editors/PackageInstallController.cs | 82 ++++++++++--------- .../Models/LocalPackageInstallModel.cs | 6 ++ src/Umbraco.Web/Models/PackageInstallModel.cs | 1 + 28 files changed, 212 insertions(+), 72 deletions(-) create mode 100644 src/Umbraco.Core/Packaging/PackageInstallType.cs diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index bab52c63f6..c068c57b08 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -128,5 +128,38 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "iconUrl")] public string IconUrl { get; set; } = string.Empty; + public PackageDefinition Clone() + { + return new PackageDefinition + { + Id = Id, + PackagePath = PackagePath, + Name = Name, + Files = new List(Files), + UmbracoVersion = (Version) UmbracoVersion.Clone(), + Version = Version, + Url = Url, + Readme = Readme, + AuthorUrl = AuthorUrl, + Author = Author, + LicenseUrl = LicenseUrl, + Actions = Actions, + PackageId = PackageId, + Control = Control, + DataTypes = new List(DataTypes), + IconUrl = IconUrl, + License = License, + Templates = new List(Templates), + Languages = new List(Languages), + Macros = new List(Macros), + Stylesheets = new List(Stylesheets), + DocumentTypes = new List(DocumentTypes), + DictionaryItems = new List(DictionaryItems), + ContentNodeId = ContentNodeId, + ContentLoadChildNodes = ContentLoadChildNodes + }; + } + } + } diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 3dee5686ff..0d533cfbc2 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -149,7 +149,7 @@ namespace Umbraco.Core.Packaging /// /// /// - public IEnumerable GetPackageActions(XElement actionsElement, string packageName) + public static IEnumerable GetPackageActions(XElement actionsElement, string packageName) { if (actionsElement == null) return Enumerable.Empty(); diff --git a/src/Umbraco.Core/Packaging/PackageInstallType.cs b/src/Umbraco.Core/Packaging/PackageInstallType.cs new file mode 100644 index 0000000000..015b994aec --- /dev/null +++ b/src/Umbraco.Core/Packaging/PackageInstallType.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Packaging +{ + public enum PackageInstallType + { + AlreadyInstalled, + NewInstall, + Upgrade + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index a31fc2d6cf..7d4d70196d 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using System.Xml.Linq; +using Semver; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; @@ -44,8 +45,26 @@ namespace Umbraco.Core.Services IEnumerable GetAllInstalledPackages(); PackageDefinition GetInstalledPackageById(int id); + PackageDefinition GetInstalledPackageByName(string name); + + /// + /// Returns a for a given package name and version + /// + /// + /// + /// If the package is an upgrade, the original/current PackageDefinition is returned + /// + PackageInstallType GetPackageInstallType(string packageName, SemVersion packageVersion, out PackageDefinition alreadyInstalled); void DeleteInstalledPackage(int packageId, int userId = 0); + /// + /// Merges the package definition information from the upgrade on to the original and returns the merged definition + /// + /// + /// + /// + PackageDefinition MergePackageDefinition(PackageDefinition original, PackageDefinition upgrade); + /// /// Persists a package definition to storage /// diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index a5c279fa21..1da53c5e11 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -7,6 +7,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using System.Xml.Linq; +using Semver; using Umbraco.Core.Collections; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; @@ -180,6 +181,86 @@ namespace Umbraco.Core.Services.Implement public PackageDefinition GetInstalledPackageById(int id) => _installedPackages.GetById(id); + public PackageDefinition GetInstalledPackageByName(string name) + { + var found = _installedPackages.GetAll().FirstOrDefault(x => x.Name.InvariantEquals(name)); + return found; + } + + public PackageInstallType GetPackageInstallType(string packageName, SemVersion packageVersion, out PackageDefinition alreadyInstalled) + { + if (packageName == null) throw new ArgumentNullException(nameof(packageName)); + if (packageVersion == null) throw new ArgumentNullException(nameof(packageVersion)); + + alreadyInstalled = GetInstalledPackageByName(packageName); + if (alreadyInstalled == null) return PackageInstallType.NewInstall; + + if (!SemVersion.TryParse(alreadyInstalled.Version, out var installedVersion)) + throw new InvalidOperationException("Could not parse the currently installed package version " + alreadyInstalled.Version); + + //compare versions + if (installedVersion >= packageVersion) return PackageInstallType.AlreadyInstalled; + + //it's an upgrade + return PackageInstallType.Upgrade; + } + + public PackageDefinition MergePackageDefinition(PackageDefinition original, PackageDefinition upgrade) + { + if (!SemVersion.TryParse(original.Version, out var originalVersion)) + throw new InvalidOperationException("Could not parse the original version"); + if(!SemVersion.TryParse(upgrade.Version, out var upgradeVersion)) + throw new InvalidOperationException("Could not parse the upgrade version"); + if (originalVersion >= upgradeVersion) + throw new InvalidOperationException("The upgrade version must be higher than the original version"); + if (!original.Name.InvariantEquals(upgrade.Name)) + throw new InvalidOperationException("Cannot merge the package definitions, the package name doesn't match"); + + var result = original.Clone(); + + result.PackagePath = upgrade.PackagePath; + result.PackageId = upgrade.PackageId; + + result.UmbracoVersion = upgrade.UmbracoVersion; + result.Version = upgrade.Version; + result.Url = upgrade.Url; + result.Readme = upgrade.Readme; + result.AuthorUrl = upgrade.AuthorUrl; + result.Author = upgrade.Author; + result.LicenseUrl = upgrade.LicenseUrl; + result.PackageId = upgrade.PackageId; + result.Control = upgrade.Control; + result.IconUrl = upgrade.IconUrl; + result.License = upgrade.License; + result.ContentNodeId = upgrade.ContentNodeId; + result.ContentLoadChildNodes = upgrade.ContentLoadChildNodes; + + result.Files = original.Files.Concat(upgrade.Files).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.DataTypes = original.DataTypes.Concat(upgrade.DataTypes).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.Templates = original.Templates.Concat(upgrade.Templates).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.Languages = original.Languages.Concat(upgrade.Languages).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.Macros = original.Macros.Concat(upgrade.Macros).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.Stylesheets = original.Stylesheets.Concat(upgrade.Stylesheets).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.DocumentTypes = original.DocumentTypes.Concat(upgrade.DocumentTypes).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + result.DictionaryItems = original.DictionaryItems.Concat(upgrade.DictionaryItems).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + + var originalActions = CompiledPackageXmlParser.GetPackageActions(XElement.Parse(result.Actions), result.Name); + var upgradeActions = CompiledPackageXmlParser.GetPackageActions(XElement.Parse(upgrade.Actions), result.Name).ToList(); + var upgradeActionsLookup = upgradeActions.ToLookup(x => x.Alias, x => x.XmlData.ToString()); + + foreach (var originalAction in originalActions) + { + var upgradeActionsWithAlias = upgradeActionsLookup[originalAction.Alias]; + + //check if the original action does not exist already in our upgrade actions + if(upgradeActionsWithAlias.All(upgradeActionXml => upgradeActionXml != originalAction.XmlData.ToString())) + upgradeActions.Add(originalAction); + } + result.Actions = new XElement("actions", upgradeActions.Select(x => x.XmlData)).ToString(); + + return result; + } + public bool SaveInstalledPackage(PackageDefinition definition) => _installedPackages.SavePackage(definition); public void DeleteInstalledPackage(int packageId, int userId = 0) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 251ecd00c1..b385e63d0c 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -458,6 +458,7 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js index b6c87027b1..ec1175ab6c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js @@ -473,7 +473,6 @@ angular.module('umbraco.mocks'). "packager_packageUpgradeInstructions": "Upgrade instructions", "packager_packageUpgradeText": " There's an upgrade available for this package. You can download it directly from the Umbraco package repository.", "packager_packageVersion": "Package version", - "packager_packageVersionHistory": "Package version history", "packager_viewPackageWebsite": "View package website", "paste_doNothing": "Paste with full formatting (Not recommended)", "paste_errorMessage": "The text you're trying to paste contains special characters or formatting. This could be caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so the pasted content will be more suitable for the web.", diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html index 5e3ef6ad1c..b657c42877 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html @@ -118,6 +118,14 @@
Version {{ vm.localPackage.version }} +

+ + + Upgrading from version + {{ vm.localPackage.originalVersion }} + + +

@@ -136,21 +144,19 @@ I accept terms of use - +
- +
@@ -165,9 +171,8 @@
- +
[DataMember(Name = "isRestarting")] public bool IsRestarting { get; set; } + } } From 94da9a66816734292471f7b600ff4d348e2954eb Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 17:25:46 +1100 Subject: [PATCH 118/223] Gets package upgrading working along with package uninstallation with multiple versions --- .../Events/UninstallPackageEventArgs.cs | 11 +- .../Packaging/IPackageInstallation.cs | 2 +- .../Packaging/PackageDataInstallation.cs | 39 +++--- .../Packaging/PackageInstallation.cs | 5 +- .../Packaging/PackagesRepository.cs | 5 - .../Services/IPackagingService.cs | 32 +++-- .../Services/Implement/PackagingService.cs | 111 +++++++----------- .../src/views/packages/edit.html | 14 +-- src/Umbraco.Web/Editors/PackageController.cs | 5 +- .../Editors/PackageInstallController.cs | 17 +-- 10 files changed, 110 insertions(+), 131 deletions(-) diff --git a/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs b/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs index 2618d04e17..63c5ceaba0 100644 --- a/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs +++ b/src/Umbraco.Core/Events/UninstallPackageEventArgs.cs @@ -3,16 +3,13 @@ using Umbraco.Core.Models.Packaging; namespace Umbraco.Core.Events { - public class UninstallPackageEventArgs : CancellableObjectEventArgs> + public class UninstallPackageEventArgs: CancellableObjectEventArgs> { - public UninstallPackageEventArgs(TEntity eventObject, IPackageInfo packageMetaData, bool canCancel) - : base(new[] { eventObject }, canCancel) + public UninstallPackageEventArgs(IEnumerable eventObject, bool canCancel) + : base(eventObject, canCancel) { - PackageMetaData = packageMetaData; } - public IPackageInfo PackageMetaData { get; } - - public IEnumerable UninstallationSummary => EventObject; + public IEnumerable UninstallationSummary => EventObject; } } diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 5dae76674d..c85a4ccd5f 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Packaging public interface IPackageInstallation { /// - /// Uninstalls a package including all data, entities and files + /// This will run the uninstallation sequence for this /// /// /// diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 36066b104f..2e9fee9595 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -228,14 +228,17 @@ namespace Umbraco.Core.Packaging } var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], null, parentId); + if (content == null) continue; + contents.Add(content); var children = (from child in root.Elements() where (string)child.Attribute("isDoc") == "" select child) .ToList(); - if (children.Any()) - contents.AddRange(CreateContentFromXml(children, content, importedContentTypes)); + + if (children.Count > 0) + contents.AddRange(CreateContentFromXml(children, content, importedContentTypes).WhereNotNull()); } return contents; } @@ -258,7 +261,7 @@ namespace Umbraco.Core.Packaging list.Add(content); //Recursive call - XElement child1 = child; + var child1 = child; var grandChildren = (from grand in child1.Elements() where (string)grand.Attribute("isDoc") == "" select grand).ToList(); @@ -272,37 +275,43 @@ namespace Umbraco.Core.Packaging private IContent CreateContentFromXml(XElement element, IContentType contentType, IContent parent, int parentId) { + var key = Guid.Empty; + if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key)) + { + //if a Key is supplied, then we need to check if the content already exists and if so we ignore the installation for this item + if (_contentService.GetById(key) != null) + return null; + } + var id = element.Attribute("id").Value; var level = element.Attribute("level").Value; var sortOrder = element.Attribute("sortOrder").Value; var nodeName = element.Attribute("nodeName").Value; var path = element.Attribute("path").Value; - //TODO: Shouldn't we be using this value??? - var template = element.Attribute("template").Value; - var key = Guid.Empty; - + var templateId = element.AttributeValue("template"); + var properties = from property in element.Elements() where property.Attribute("isDoc") == null select property; + var template = templateId.HasValue ? _fileService.GetTemplate(templateId.Value) : null; + IContent content = parent == null ? new Content(nodeName, parentId, contentType) { Level = int.Parse(level), - SortOrder = int.Parse(sortOrder) + SortOrder = int.Parse(sortOrder), + TemplateId = template?.Id, + Key = key } : new Content(nodeName, parent, contentType) { Level = int.Parse(level), - SortOrder = int.Parse(sortOrder) + SortOrder = int.Parse(sortOrder), + TemplateId = template?.Id, + Key = key }; - if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key)) - { - // update the Guid (for UDI support) - content.Key = key; - } - foreach (var property in properties) { string propertyTypeAlias = property.Name.LocalName; diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index d7bb72836e..955662f3fe 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -76,12 +76,13 @@ namespace Umbraco.Core.Packaging return files; } + /// public UninstallationSummary UninstallPackage(PackageDefinition package, int userId) { //running this will update the PackageDefinition with the items being removed var summary = _packageDataInstallation.UninstallPackageData(package, userId); - summary.Actions = _parser.GetPackageActions(XElement.Parse(package.Actions), package.Name); + summary.Actions = CompiledPackageXmlParser.GetPackageActions(XElement.Parse(package.Actions), package.Name); //run actions before files are removed summary.ActionErrors = UndoPackageActions(package, summary.Actions).ToList(); @@ -109,7 +110,7 @@ namespace Umbraco.Core.Packaging installationSummary.StylesheetsInstalled = _packageDataInstallation.ImportStylesheets(compiledPackage.Stylesheets, userId); installationSummary.ContentInstalled = _packageDataInstallation.ImportContent(compiledPackage.Documents, importedDocTypes, userId); - installationSummary.Actions = _parser.GetPackageActions(XElement.Parse(compiledPackage.Actions), compiledPackage.Name); + installationSummary.Actions = CompiledPackageXmlParser.GetPackageActions(XElement.Parse(compiledPackage.Actions), compiledPackage.Name); installationSummary.MetaData = compiledPackage; installationSummary.FilesInstalled = packageDefinition.Files; diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index af5c7ffded..249d02a320 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -120,11 +120,6 @@ namespace Umbraco.Core.Packaging if (definition.Id == default) { - //check if the name already exists - var existsByName = packagesXml.Root.Elements("package").Any(x => x.AttributeValue("name") == definition.Name); - if (existsByName) - return false; - //need to gen an id and persist // Find max id var maxId = packagesXml.Root.Elements("package").Max(x => x.AttributeValue("id")) ?? 0; diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 7d4d70196d..c14882fe7a 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -37,15 +37,35 @@ namespace Umbraco.Core.Services /// InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); - UninstallationSummary UninstallPackage(PackageDefinition packageDefinition, int userId = 0); + /// + /// Uninstalls all versions of the package by name + /// + /// + /// + /// + UninstallationSummary UninstallPackage(string packageName, int userId = 0); #endregion #region Installed Packages IEnumerable GetAllInstalledPackages(); + + /// + /// Returns the for the installation id + /// + /// + /// PackageDefinition GetInstalledPackageById(int id); - PackageDefinition GetInstalledPackageByName(string name); + + /// + /// Returns all for the package by name + /// + /// + /// + /// A list of all package definitions installed for this package (i.e. original install and any upgrades) + /// + IEnumerable GetInstalledPackageByName(string name); /// /// Returns a for a given package name and version @@ -57,14 +77,6 @@ namespace Umbraco.Core.Services PackageInstallType GetPackageInstallType(string packageName, SemVersion packageVersion, out PackageDefinition alreadyInstalled); void DeleteInstalledPackage(int packageId, int userId = 0); - /// - /// Merges the package definition information from the upgrade on to the original and returns the merged definition - /// - /// - /// - /// - PackageDefinition MergePackageDefinition(PackageDefinition original, PackageDefinition upgrade); - /// /// Persists a package definition to storage /// diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 1da53c5e11..24ef818624 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -44,7 +44,7 @@ namespace Umbraco.Core.Services.Implement ICreatedPackagesRepository createdPackages, IInstalledPackagesRepository installedPackages, IPackageInstallation packageInstallation) - { + { _auditService = auditService; _createdPackages = createdPackages; _installedPackages = installedPackages; @@ -110,7 +110,7 @@ namespace Umbraco.Core.Services.Implement if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFile); var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId).ToList(); - + SaveInstalledPackage(packageDefinition); _auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package files installed for package '{compiledPackage.Name}'."); @@ -141,16 +141,44 @@ namespace Umbraco.Core.Services.Implement return summary; } - public UninstallationSummary UninstallPackage(PackageDefinition package, int userId = 0) + public UninstallationSummary UninstallPackage(string packageName, int userId = 0) { - var summary = _packageInstallation.UninstallPackage(package, userId); - - SaveInstalledPackage(package); + //this is ordered by descending version + var allPackageVersions = GetInstalledPackageByName(packageName)?.ToList(); + if (allPackageVersions == null || allPackageVersions.Count == 0) + throw new InvalidOperationException("No installed package found by name " + packageName); - DeleteInstalledPackage(package.Id, userId); + var summary = new UninstallationSummary + { + MetaData = allPackageVersions[0] + }; + + var allSummaries = new List(); + + foreach (var packageVersion in allPackageVersions) + { + var versionUninstallSummary = _packageInstallation.UninstallPackage(packageVersion, userId); + + allSummaries.Add(versionUninstallSummary); + + //merge the summary + summary.ActionErrors = summary.ActionErrors.Concat(versionUninstallSummary.ActionErrors).Distinct().ToList(); + summary.Actions = summary.Actions.Concat(versionUninstallSummary.Actions).Distinct().ToList(); + summary.DataTypesUninstalled = summary.DataTypesUninstalled.Concat(versionUninstallSummary.DataTypesUninstalled).Distinct().ToList(); + summary.DictionaryItemsUninstalled = summary.DictionaryItemsUninstalled.Concat(versionUninstallSummary.DictionaryItemsUninstalled).Distinct().ToList(); + summary.DocumentTypesUninstalled = summary.DocumentTypesUninstalled.Concat(versionUninstallSummary.DocumentTypesUninstalled).Distinct().ToList(); + summary.FilesUninstalled = summary.FilesUninstalled.Concat(versionUninstallSummary.FilesUninstalled).Distinct().ToList(); + summary.LanguagesUninstalled = summary.LanguagesUninstalled.Concat(versionUninstallSummary.LanguagesUninstalled).Distinct().ToList(); + summary.MacrosUninstalled = summary.MacrosUninstalled.Concat(versionUninstallSummary.MacrosUninstalled).Distinct().ToList(); + summary.StylesheetsUninstalled = summary.StylesheetsUninstalled.Concat(versionUninstallSummary.StylesheetsUninstalled).Distinct().ToList(); + summary.TemplatesUninstalled = summary.TemplatesUninstalled.Concat(versionUninstallSummary.TemplatesUninstalled).Distinct().ToList(); + + SaveInstalledPackage(packageVersion); + DeleteInstalledPackage(packageVersion.Id, userId); + } // trigger the UninstalledPackage event - UninstalledPackage.RaiseEvent(new UninstallPackageEventArgs(summary, package, false), this); + UninstalledPackage.RaiseEvent(new UninstallPackageEventArgs(allSummaries, false), this); return summary; } @@ -181,9 +209,9 @@ namespace Umbraco.Core.Services.Implement public PackageDefinition GetInstalledPackageById(int id) => _installedPackages.GetById(id); - public PackageDefinition GetInstalledPackageByName(string name) + public IEnumerable GetInstalledPackageByName(string name) { - var found = _installedPackages.GetAll().FirstOrDefault(x => x.Name.InvariantEquals(name)); + var found = _installedPackages.GetAll().Where(x => x.Name.InvariantEquals(name)).OrderByDescending(x => SemVersion.Parse(x.Version)); return found; } @@ -192,7 +220,8 @@ namespace Umbraco.Core.Services.Implement if (packageName == null) throw new ArgumentNullException(nameof(packageName)); if (packageVersion == null) throw new ArgumentNullException(nameof(packageVersion)); - alreadyInstalled = GetInstalledPackageByName(packageName); + //get the latest version installed + alreadyInstalled = GetInstalledPackageByName(packageName)?.OrderByDescending(x => SemVersion.Parse(x.Version)).FirstOrDefault(); if (alreadyInstalled == null) return PackageInstallType.NewInstall; if (!SemVersion.TryParse(alreadyInstalled.Version, out var installedVersion)) @@ -205,62 +234,6 @@ namespace Umbraco.Core.Services.Implement return PackageInstallType.Upgrade; } - public PackageDefinition MergePackageDefinition(PackageDefinition original, PackageDefinition upgrade) - { - if (!SemVersion.TryParse(original.Version, out var originalVersion)) - throw new InvalidOperationException("Could not parse the original version"); - if(!SemVersion.TryParse(upgrade.Version, out var upgradeVersion)) - throw new InvalidOperationException("Could not parse the upgrade version"); - if (originalVersion >= upgradeVersion) - throw new InvalidOperationException("The upgrade version must be higher than the original version"); - if (!original.Name.InvariantEquals(upgrade.Name)) - throw new InvalidOperationException("Cannot merge the package definitions, the package name doesn't match"); - - var result = original.Clone(); - - result.PackagePath = upgrade.PackagePath; - result.PackageId = upgrade.PackageId; - - result.UmbracoVersion = upgrade.UmbracoVersion; - result.Version = upgrade.Version; - result.Url = upgrade.Url; - result.Readme = upgrade.Readme; - result.AuthorUrl = upgrade.AuthorUrl; - result.Author = upgrade.Author; - result.LicenseUrl = upgrade.LicenseUrl; - result.PackageId = upgrade.PackageId; - result.Control = upgrade.Control; - result.IconUrl = upgrade.IconUrl; - result.License = upgrade.License; - result.ContentNodeId = upgrade.ContentNodeId; - result.ContentLoadChildNodes = upgrade.ContentLoadChildNodes; - - result.Files = original.Files.Concat(upgrade.Files).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.DataTypes = original.DataTypes.Concat(upgrade.DataTypes).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.Templates = original.Templates.Concat(upgrade.Templates).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.Languages = original.Languages.Concat(upgrade.Languages).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.Macros = original.Macros.Concat(upgrade.Macros).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.Stylesheets = original.Stylesheets.Concat(upgrade.Stylesheets).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.DocumentTypes = original.DocumentTypes.Concat(upgrade.DocumentTypes).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - result.DictionaryItems = original.DictionaryItems.Concat(upgrade.DictionaryItems).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - - var originalActions = CompiledPackageXmlParser.GetPackageActions(XElement.Parse(result.Actions), result.Name); - var upgradeActions = CompiledPackageXmlParser.GetPackageActions(XElement.Parse(upgrade.Actions), result.Name).ToList(); - var upgradeActionsLookup = upgradeActions.ToLookup(x => x.Alias, x => x.XmlData.ToString()); - - foreach (var originalAction in originalActions) - { - var upgradeActionsWithAlias = upgradeActionsLookup[originalAction.Alias]; - - //check if the original action does not exist already in our upgrade actions - if(upgradeActionsWithAlias.All(upgradeActionXml => upgradeActionXml != originalAction.XmlData.ToString())) - upgradeActions.Add(originalAction); - } - result.Actions = new XElement("actions", upgradeActions.Select(x => x.XmlData)).ToString(); - - return result; - } - public bool SaveInstalledPackage(PackageDefinition definition) => _installedPackages.SavePackage(definition); public void DeleteInstalledPackage(int packageId, int userId = 0) @@ -289,10 +262,10 @@ namespace Umbraco.Core.Services.Implement /// /// Occurs after a package is uninstalled /// - public static event TypedEventHandler> UninstalledPackage; + public static event TypedEventHandler UninstalledPackage; #endregion - + } } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index a66eb94746..8ed1a43e8a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -133,7 +133,7 @@ -
+
/// The content. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// One or more content type alias. /// The children of the content, of any of the specified types. public static IEnumerable Children(this IPublishedContent content, string culture = null, params string[] alias) @@ -1078,6 +1085,7 @@ namespace Umbraco.Web ///
/// The content type. /// The content. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The children of content, of the given content type. /// /// Children are sorted by their sortOrder. @@ -1127,6 +1135,7 @@ namespace Umbraco.Web /// The content. /// A service context. /// An optional content type alias. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The children of the content. public static DataTable ChildrenAsTable(this IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null) { @@ -1139,6 +1148,7 @@ namespace Umbraco.Web /// The content. /// A service context. /// An optional content type alias. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The children of the content. private static DataTable GenerateDataTable(IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null) { From 5ebf51e6df64419c6676051624237a6a7ca8bcc7 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 16 Jan 2019 08:40:00 +0100 Subject: [PATCH 123/223] #3417 added mockup of parameter editing --- .../src/views/macros/edit.html | 5 +- .../infiniteeditors/parameter.controller.js | 27 +++++++ .../macros/infiniteeditors/parameter.html | 58 ++++++++++++++ .../views/macros/macros.edit.controller.js | 30 ++++++- .../views/macro.parameters.controller.js | 78 +++++++++++++++++++ .../src/views/macros/views/parameters.html | 31 +++++++- 6 files changed, 223 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/edit.html b/src/Umbraco.Web.UI.Client/src/views/macros/edit.html index 911dcf0c9e..ddb5f98781 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/edit.html @@ -1,7 +1,6 @@ -
- - +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js index ef65c77e1d..81c699a05f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js @@ -6,7 +6,7 @@ * @description * The controller for editing macros. */ -function MacrosEditController($scope, $routeParams, macroResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService) { +function MacrosEditController($scope, $routeParams, macroResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService, angularHelper) { var vm = this; @@ -17,6 +17,7 @@ function MacrosEditController($scope, $routeParams, macroResource, editorState, vm.save = saveMacro; vm.toggle = toggleValue; + init(); @@ -50,11 +51,25 @@ function MacrosEditController($scope, $routeParams, macroResource, editorState, "cachePeriod": 2400, "cacheByPage": true, "cacheByUser": false, - "view" : "Second" + "view": "Second", + "parameters": [ + { + "key": "title", + "label": "Label", + "editor": "editor" + }, + { + "key": "link", + "label": "Link", + "editor": "Link picker" + } + ] } vm.views = ['First', 'Second', 'Third']; + vm.parameterEditors = ['editor', 'Link picker', 'Image picker']; + vm.page.loading = false; } @@ -82,6 +97,17 @@ function MacrosEditController($scope, $routeParams, macroResource, editorState, //}); } } + + function setFormDirty() { + var currentForm = angularHelper.getCurrentForm($scope); + + if (currentForm) { + + currentForm.$setDirty(); + } + } + + vm.setDirty = setFormDirty; } angular.module("umbraco").controller("Umbraco.Editors.Macros.EditController", MacrosEditController); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js new file mode 100644 index 0000000000..851b537c3b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js @@ -0,0 +1,78 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.ParametersController + * @function + * + * @description + * The controller for editing macros parameters + */ +function MacrosParametersController($scope, editorService) { + + $scope.sortableOptions = { + axis: 'y', + containment: 'parent', + cursor: 'move', + items: 'div.umb-stylesheet-rules__listitem', + handle: '.handle', + tolerance: 'pointer', + update: function (e, ui) { + $scope.model.setDirty(); + } + }; + + + $scope.remove = function (parameter, evt) { + evt.preventDefault(); + + $scope.model.macro.parameters = _.without($scope.model.macro.parameters, parameter); + $scope.model.setDirty(); + } + + $scope.add = function (evt) { + evt.preventDefault(); + + openOverlay({}, 'Add parameter', (newParameter) => { + if (!$scope.model.macro.parameters) { + $scope.model.macro.parameters = []; + } + $scope.model.macro.parameters.push(newParameter); + $scope.model.setDirty(); + }); + } + + $scope.edit = function (parameter, evt) { + evt.preventDefault(); + + openOverlay(parameter,'Edit parameter', (newParameter) => { + parameter.key = newParameter.key; + parameter.label = newParameter.label; + parameter.editor = newParameter.editor; + parameter.editor = newParameter.editor; + $scope.model.setDirty(); + }); + } + + function openOverlay(parameter, title, onSubmit) { + + const ruleDialog = { + title: title, + parameter: _.clone(parameter), + editors : $scope.model.parameterEditors, + view: "views/macros/infiniteeditors/parameter.html", + size: "small", + submit: function (model) { + onSubmit(model.parameter); + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + + editorService.open(ruleDialog); + + } + +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.ParametersController", MacrosParametersController); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html index 6a10d4f80b..91231a49b7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html @@ -1,3 +1,32 @@  - + +
+
+
Parameters
+ Define the parameters hat should be available when using his macro +
+
+
+
+
+ +
+ {{parameter.label}} +
+
+ Remove +
+
+
+ + +
+
+
+ +
From 31545db91ed33ad59a4049a91792d11edbee02a6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 19:29:42 +1100 Subject: [PATCH 124/223] Fixes routing with the packages section --- src/Umbraco.Web.UI.Client/src/routes.js | 13 ++++++++--- .../src/views/packages/edit.controller.js | 4 ++-- .../src/views/packages/overview.controller.js | 22 +++++++++---------- .../Trees/PackagesTreeController.cs | 2 +- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js index 2d8ad46371..64bddb16e2 100644 --- a/src/Umbraco.Web.UI.Client/src/routes.js +++ b/src/Umbraco.Web.UI.Client/src/routes.js @@ -149,14 +149,21 @@ app.config(function ($routeProvider) { .when('/:section/:tree/:method?', { //This allows us to dynamically change the template for this route since you cannot inject services into the templateUrl method. template: "
", - //This controller will execute for this route, then we replace the template dynamnically based on the current tree. - controller: function ($scope, $route, $routeParams, treeService) { + //This controller will execute for this route, then we replace the template dynamically based on the current tree. + controller: function ($scope, $routeParams, treeService) { if (!$routeParams.method) { $scope.templateUrl = "views/common/dashboard.html"; + return; } - // Here we need to figure out if this route is for a package tree and if so then we need + //special case for the package section + if ($routeParams.section.toLowerCase() === "packages" && $routeParams.tree.toLowerCase() === "packages" && $routeParams.method !== "edit") { + $scope.templateUrl = "views/packages/overview.html"; + return; + } + + // Here we need to figure out if this route is for a user's package tree and if so then we need // to change it's convention view path to: // /App_Plugins/{mypackage}/backoffice/{treetype}/{method}.html diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 4afe62786e..29d871c0b1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -130,7 +130,7 @@ } function back() { - $location.path("packages/packages/overview").search('create', null);; + $location.path("packages/packages/created").search("create", null); } function createOrUpdatePackage(editPackageForm) { @@ -148,7 +148,7 @@ if (create) { //if we are creating, then redirect to the correct url and reload - $location.path("packages/packages/edit/" + vm.package.id).search("subview", "created").search("create", null); + $location.path("packages/packages/edit/" + vm.package.id).search("create", null); //don't add a browser history for this $location.replace(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index ccd86c6f6c..59fa79dc26 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesOverviewController($scope, $location, localStorageService) { + function PackagesOverviewController($scope, $location, $routeParams, localStorageService) { //Hack! // if there is a cookie value for packageInstallUri then we need to redirect there, @@ -10,7 +10,7 @@ // we will refresh and then navigate there. let installPackageUri = localStorageService.get("packageInstallUri"); - let packageUri = $location.search().subview; + let packageUri = $routeParams.method; if (installPackageUri) { localStorageService.remove("packageInstallUri"); @@ -33,10 +33,10 @@ "name": "Packages", "icon": "icon-cloud", "view": "views/packages/views/repo.html", - "active": !packageUri || packageUri === "navigation", + "active": !packageUri || packageUri === "repo", "alias": "umbPackages", - "action": function() { - $location.search("subview", "navigation"); + "action": function () { + $location.path("/packages/packages/repo"); } }, { @@ -45,8 +45,8 @@ "view": "views/packages/views/installed.html", "active": packageUri === "installed", "alias": "umbInstalled", - "action": function() { - $location.search("subview", "installed"); + "action": function () { + $location.path("/packages/packages/installed"); } }, { @@ -55,8 +55,8 @@ "view": "views/packages/views/install-local.html", "active": packageUri === "local", "alias": "umbInstallLocal", - "action": function() { - $location.search("subview", "local"); + "action": function () { + $location.path("/packages/packages/local"); } }, { @@ -65,8 +65,8 @@ "view": "views/packages/views/created.html", "active": packageUri === "created", "alias": "umbCreatedPackages", - "action": function() { - $location.search("subview", "created"); + "action": function () { + $location.path("/packages/packages/created"); } } ]; diff --git a/src/Umbraco.Web/Trees/PackagesTreeController.cs b/src/Umbraco.Web/Trees/PackagesTreeController.cs index fdc5294aa2..68b67f9fe2 100644 --- a/src/Umbraco.Web/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/PackagesTreeController.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Trees var root = base.CreateRootNode(queryStrings); //this will load in a custom UI instead of the dashboard for the root node - root.RoutePath = $"{Constants.Applications.Packages}/{Constants.Trees.Packages}/overview"; + root.RoutePath = $"{Constants.Applications.Packages}/{Constants.Trees.Packages}/repo"; root.Icon = "icon-box"; root.HasChildren = false; From 572c6989ceadb4edccfad2238ca1258510be4d1e Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 19:30:07 +1100 Subject: [PATCH 125/223] Changes control to view for the package view --- .../Models/Packaging/CompiledPackage.cs | 2 +- .../Models/Packaging/IPackageInfo.cs | 7 +++- .../Models/Packaging/PackageDefinition.cs | 41 +++---------------- .../Packaging/CompiledPackageXmlParser.cs | 2 +- .../Packaging/PackageDefinitionXmlParser.cs | 4 +- .../Packaging/PackagesRepository.cs | 6 +-- .../src/views/packages/edit.controller.js | 14 +++---- .../src/views/packages/edit.html | 6 +-- .../Editors/PackageInstallController.cs | 7 ++-- 9 files changed, 32 insertions(+), 57 deletions(-) diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index a852fcc997..f14fe47bfe 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Models.Packaging public string Author { get; set; } public string AuthorUrl { get; set; } public string Readme { get; set; } - public string Control { get; set; } + public string PackageView { get; set; } public string IconUrl { get; set; } public string Actions { get; set; } //fixme: Should we make this strongly typed to IEnumerable ? diff --git a/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs b/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs index 8722ee7811..eea56549f1 100644 --- a/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs +++ b/src/Umbraco.Core/Models/Packaging/IPackageInfo.cs @@ -13,7 +13,12 @@ namespace Umbraco.Core.Models.Packaging string Author { get; } string AuthorUrl { get; } string Readme { get; } - string Control { get; } //fixme - this needs to be an angular view + + /// + /// This is the angular view path that will be loaded when the package installs + /// + string PackageView { get; } + string IconUrl { get; } } } diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index c068c57b08..8c0ef79d0b 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Models.Packaging Actions = compiled.Actions, Author = compiled.Author, AuthorUrl = compiled.AuthorUrl, - Control = compiled.Control, + PackageView = compiled.PackageView, IconUrl = compiled.IconUrl, License = compiled.License, LicenseUrl = compiled.LicenseUrl, @@ -115,9 +115,9 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "files")] public IList Files { get; set; } = new List(); - //fixme: Change this to angular view - [DataMember(Name = "loadControl")] - public string Control { get; set; } = string.Empty; + /// + [DataMember(Name = "packageView")] + public string PackageView { get; set; } = string.Empty; [DataMember(Name = "actions")] public string Actions { get; set; } = ""; @@ -127,38 +127,7 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "iconUrl")] public string IconUrl { get; set; } = string.Empty; - - public PackageDefinition Clone() - { - return new PackageDefinition - { - Id = Id, - PackagePath = PackagePath, - Name = Name, - Files = new List(Files), - UmbracoVersion = (Version) UmbracoVersion.Clone(), - Version = Version, - Url = Url, - Readme = Readme, - AuthorUrl = AuthorUrl, - Author = Author, - LicenseUrl = LicenseUrl, - Actions = Actions, - PackageId = PackageId, - Control = Control, - DataTypes = new List(DataTypes), - IconUrl = IconUrl, - License = License, - Templates = new List(Templates), - Languages = new List(Languages), - Macros = new List(Macros), - Stylesheets = new List(Stylesheets), - DocumentTypes = new List(DocumentTypes), - DictionaryItems = new List(DictionaryItems), - ContentNodeId = ContentNodeId, - ContentLoadChildNodes = ContentLoadChildNodes - }; - } + } diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 0d533cfbc2..7f62f4fd27 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -51,7 +51,7 @@ namespace Umbraco.Core.Packaging IconUrl = package.Element("iconUrl")?.Value, UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type"), true), - Control = package.Element("control")?.Value, + PackageView = package.Element("view")?.Value, Actions = xml.Root.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value Files = xml.Root.Element("files")?.Elements("file")?.Select(CompiledPackageFile.Create).ToList() ?? new List(), Macros = xml.Root.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 45e6fd9845..00255fa43a 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -50,7 +50,7 @@ namespace Umbraco.Core.Packaging DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), DataTypes = xml.Element("datatypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), Files = xml.Element("files")?.Elements("file").Select(x => x.Value).ToList() ?? new List(), - Control = xml.Element("loadcontrol")?.Value ?? string.Empty + PackageView = xml.Element("view")?.Value ?? string.Empty }; return retVal; @@ -101,7 +101,7 @@ namespace Umbraco.Core.Packaging new XElement("files", (def.Files ?? Array.Empty()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))), new XElement("languages", string.Join(",", def.Languages ?? Array.Empty())), new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty())), - new XElement("loadcontrol", def.Control ?? string.Empty)); //fixme: no more loadcontrol, needs to be an angular view + new XElement("view", def.PackageView ?? string.Empty)); return packageXml; } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index 249d02a320..5531e05705 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -180,10 +180,10 @@ namespace Umbraco.Core.Packaging AppendFileToManifest(fileName, temporaryPath, filesXml); //Load control on install... - if (!string.IsNullOrEmpty(definition.Control)) + if (!string.IsNullOrEmpty(definition.PackageView)) { - var control = new XElement("control", definition.Control); - AppendFileToManifest(definition.Control, temporaryPath, filesXml); + var control = new XElement("view", definition.PackageView); + AppendFileToManifest(definition.PackageView, temporaryPath, filesXml); manifestRoot.Add(control); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 29d871c0b1..ca20b33a3e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -19,8 +19,8 @@ vm.openContentPicker = openContentPicker; vm.openFilePicker = openFilePicker; vm.removeFile = removeFile; - vm.openControlPicker = openControlPicker; - vm.removeControl = removeControl; + vm.openViewPicker = openViewPicker; + vm.removePackageView = removePackageView; vm.downloadFile = downloadFile; const packageId = $routeParams.id; @@ -220,16 +220,16 @@ vm.package.files.splice(index, 1); } - function openControlPicker() { + function openViewPicker() { const controlPicker = { - title: "Select control", + title: "Select view", section: "settings", treeAlias: "files", entityType: "file", onlyInitialized: false, select: function(node) { const id = unescape(node.id); - vm.package.loadControl = id; + vm.package.packageView = id; editorService.close(); }, close: function() { @@ -239,8 +239,8 @@ editorService.treePicker(controlPicker); } - function removeControl() { - vm.package.loadControl = null; + function removePackageView() { + vm.package.packageView = null; } onInit(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 8ed1a43e8a..5163fadfb5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -264,14 +264,14 @@ name="vm.package.loadControl" allow-edit="true" allow-remove="true" - on-edit="vm.openControlPicker()" - on-remove="vm.removeControl()"> + on-edit="vm.openViewPicker()" + on-remove="vm.removePackageView()"> Add diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index dd7c4302c5..544a871720 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -376,10 +376,11 @@ namespace Umbraco.Web.Editors zipFile.Delete(); var redirectUrl = ""; - if (packageInfo.Control.IsNullOrWhiteSpace() == false) + if (!packageInfo.PackageView.IsNullOrWhiteSpace()) { - //fixme: this needs to be replaced with an angular view the installer.aspx no longer exists. - //redirectUrl = string.Format("/developer/framed/{0}", + //fixme! + throw new NotImplementedException(); + //redirectUrl = string.Format("/packages/framed/{0}", // Uri.EscapeDataString( // string.Format("/umbraco/developer/Packages/installer.aspx?installing=custominstaller&dir={0}&pId={1}&customControl={2}&customUrl={3}", tempDir, model.Id, ins.Control, ins.Url))); } From 26b31f1fc88598bb1a201c55c4c06d269ceec438 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 10:01:04 +0100 Subject: [PATCH 126/223] Fix Git repository issue with casing of some filepaths --- src/Umbraco.Web.UI/umbraco/config/lang/nb.xml | 963 ------------- .../umbraco/config/lang/zh_tw.xml | 1269 ----------------- 2 files changed, 2232 deletions(-) delete mode 100644 src/Umbraco.Web.UI/umbraco/config/lang/nb.xml delete mode 100644 src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml deleted file mode 100644 index d51d41e558..0000000000 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml +++ /dev/null @@ -1,963 +0,0 @@ - - - - The Umbraco community - http://our.umbraco.org/documentation/Extending-Umbraco/Language-Files - - - Angi domene - Revisjoner - Bla gjennom - Skift dokumenttype - Kopier - Opprett - Opprett pakke - Slett - Deaktiver - Tøm papirkurv - Eksporter dokumenttype - Importer dokumenttype - Importer pakke - Rediger i Canvas - Logg av - Flytt - Varslinger - Offentlig tilgang - Publiser - Avpubliser - Oppdater noder - Republiser hele siten - Gjenopprett - Rettigheter - Reverser - Send til publisering - Send til oversetting - Sorter - Oversett - Oppdater - - - Ingen tilgang. - Legg til domene - Fjern - Ugyldig node. - Ugyldig domeneformat. - Domene er allerede tilknyttet. - Språk - Domene - Domene '%0%' er nå opprettet og tilknyttet siden - Domenet '%0%' er nå slettet - Domenet '%0%' er allerede tilknyttet - Domenet '%0%' er nå oppdatert - eller rediger eksisterende domener -
Stier med ett nivå støttes, f.eks. "eksempel.com/no". Imidlertid bør det unngås. Bruk heller språkinnstillingen over.]]>
- Arv - Språk - Vil også gjelde denne noden, med mindre et underordnet domene også gjelder.]]> - Domener - - - Viser for - - - Velg - Gjør noe annet - Fet - Reduser innrykk - Sett inn skjemafelt - Sett inn grafisk overskrift - Rediger HTML - Øk innrykk - Kursiv - Midtstill - Juster tekst venstre - Juster tekst høyre - Sett inn lenke - Sett inn lokal lenke (anker) - Punktmerking - Nummerering - Sett inn makro - Sett inn bilde - Rediger relasjoner - Tilbake til listen - Lagre - Lagre og publiser - Lagre og planlegge - Lagre og send til publisering - Forhåndsvis - Forhåndsvisning er deaktivert siden det ikke er angitt noen mal - Velg formattering - Vis stiler - Sett inn tabell - - - For å endre det valge innholdets dokumenttype, velger du først en ny dokumenttype som er gyldig på gjeldende plassering. - Kontroller deretter at alle egenskaper blir overført riktig til den nye dokumenttypen og klikk på Lagre. - Innholdet har blitt republisert. - Nåværende egenskap - Nåværende type - Du kan ikke endre dokumenttype, ettersom det ikke er andre gyldige dokumenttyper på denne plasseringen. - Dokumenttype endret - Overfør egenskaper - Overfør til egenskap - Ny mal - Ny type - ingen - Innhold - Velg ny dokumenttype - Dokumenttypen på det valgte innhold ble endret til [new type], og følgende egenskaper ble overført: - til - Overføringen av egenskaper kunne ikke fullføres da en eller flere egenskaper er satt til å bli overført mer enn en gang. - Kun andre dokumenttyper som er gyldige for denne plasseringen vises. - - - Publisert - Om siden - Alias - (hvordan du ville beskrevet bildet over telefon) - Alternative lenker - Klikk for å redigere denne noden - Opprettet av - Opprinnelig forfatter - Oppdatert av - Opprettet den - Tidspunkt for opprettelse - Dokumenttype - Redigerer - Utløpsdato - Denne noden er endret siden siste publisering - Denne noden er enda ikke publisert - Sist publisert - Det er ingen elementer å vise i listen. - Mediatype - Link til media - Medlemsgruppe - Rolle - Medlemstype - Ingen dato valgt - Sidetittel - Egenskaper - Dette dokumentet er publisert, men ikke synlig ettersom den overliggende siden '%0%' ikke er publisert - Intern feil: dokumentet er publisert men finnes ikke i hurtigbuffer - Publisert - Publiseringsstatus - Publiseringsdato - Dato for avpublisering - Fjern dato - Sorteringsrekkefølgen er oppdatert - Trekk og slipp nodene eller klikk på kolonneoverskriftene for å sortere. Du kan velge flere noder ved å holde shift eller control tastene mens du velger. - Statistikk - Tittel (valgfri) - Alternativ tekst (valgfri) - Type - Avpubliser - Sist endret - Tidspunkt for siste endring - Fjern fil - Lenke til dokument - Medlem av gruppe(ne) - Ikke medlem av gruppe(ne) - Undersider - Åpne i vindu - - - Klikk for å laste opp - - - Opprett et nytt medlem - Alle medlemmer - - - Hvor ønsker du å oprette den nye %0% - Opprett under - Velg en type og skriv en tittel - "dokumenttyper".]]> - "mediatyper".]]> - - - Til ditt nettsted - - Skjul - Hvis Umbraco ikke starter, kan det skyldes at pop-up vinduer ikke er tillatt - er åpnet i nytt vindu - Omstart - Besøk - Velkommen - - - Stay - Discard changes - You have unsaved changes - Are you sure you want to navigate away from this page? - you have unsaved changes - - - Done - Deleted %0% item - Deleted %0% items - Deleted %0% out of %1% item - Deleted %0% out of %1% items - Published %0% item - Published %0% items - Published %0% out of %1% item - Published %0% out of %1% items - Unpublished %0% item - Unpublished %0% items - Unpublished %0% out of %1% item - Unpublished %0% out of %1% items - Moved %0% item - Moved %0% items - Moved %0% out of %1% item - Moved %0% out of %1% items - Copied %0% item - Copied %0% items - Copied %0% out of %1% item - Copied %0% out of %1% items - - - Navn på lokal link - Rediger domener - Lukk dette vinduet - Er du sikker på at du vil slette - Er du sikker på at du vil deaktivere - Er du sikker på at du vil forlate Umbraco? - Er du sikker? - Klipp ut - Rediger ordboksnøkkel - Rediger språk - Sett inn lokal link - Sett inn spesialtegn - Sett inn grafisk overskrift - Sett inn bilde - Sett inn lenke - Sett inn makro - Sett inn tabell - Sist redigert - Lenke - Intern link: - Ved lokal link, sett inn "#" foran link - Åpne i nytt vindu? - Makroinnstillinger - Denne makroen har ingen egenskaper du kan endre - Lim inn - Endre rettigheter for - Innholdet i papirkurven blir nå slettet. Vennligst ikke lukk dette vinduet mens denne operasjonen foregår - Papirkurven er nå tom - Når elementer blir slettet fra papirkurven vil de være slettet for alltid - regexlib.com tjenesten opplever for tiden problemer som vi ikke har kontroll over. Vi beklager denne ubeleiligheten.]]> - Søk etter et regulært uttrykk for å legge inn validering til et felt. Eksempel: 'email, 'zip-code' 'url' - Fjern makro - Obligatorisk - Nettstedet er indeksert - Hurtigbufferen er blitt oppdatert. Alt publisert innhold er nå à jour. Alt upublisert innhold er fortsatt ikke publisert. - Hurtigbufferen for siden vil bli oppdatert. Alt publisert innhold vil bli oppdatert, mens upublisert innhold vil forbli upublisert. - Antall kolonner - Antall rader - Sett en plassholder-ID
Ved å sette en ID på plassholderen kan du legge inn innhold i denne malen fra underliggende maler, ved å referere denne ID'en ved hjelp av et <asp:content /> element.]]>
- Velg en plassholder ID fra listen under. Du kan bare velge ID'er fra den gjeldende malens overordnede mal.]]> - Klikk på bildet for å se det i full størrelse - Velg punkt - Se buffret node - - - %0%' under.
Du kan legge til flere språk under 'språk' i menyen til venstre.]]>
- Språk - - - Skriv inn ditt brukernavn - Skriv inn ditt passord - Navngi %0%... - Skriv inn navn... - Søk... - Filtrer... - Skriv inn nøkkelord (trykk på Enter etter hvert nøkkelord)... - - - Tillatte underordnede noder - Opprett - Slett arkfane - Beskrivelse - Ny arkfane - Arkfane - Miniatyrbilde - Opprett brukerdefinert listevisning - Fjern brukerdefinert listevisning - - - Legg til forhåndsverdi - Database datatype - Kontrollelement GUID - Kontrollelement - Knapper - Aktiver avanserte instillinger for - Aktiver kontektsmeny - Maksimum standard størrelse på innsatte bilder - Beslektede stilark - Vis etikett - Bredde og høyde - - - Dine data har blitt lagret, men før du kan publisere denne siden må du rette noen feil: - Den gjeldende Membership Provider støtter ikke endring av passord. (EnablePasswordRetrieval må være satt til sann) - %0% finnes allerede - Det var feil i dokumentet: - Det var feil i skjemaet: - Passordet bør være minst %0% tegn og inneholde minst %1% numeriske tegn - %0% må være et heltall - %0% under %1% er obligatorisk - %0% er obligatorisk - %0% under %1% er ikke i et korrekt format - %0% er ikke i et korrekt format - - - Filtypen er deaktivert av administrator - NB! Selv om CodeMirror er aktivert i konfigurasjon er det deaktivert i Internet Explorer pga. ustabilitet. - Fyll ut både alias og navn på den nye egenskapstypen! - Det er et problem med lese/skrive rettighetene til en fil eller mappe - Tittel mangler - Type mangler - Du er i ferd med å gjøre bildet større enn originalen. Det vil forringe kvaliteten på bildet, ønsker du å fortsette? - Startnode er slettet. Kontakt din administrator - Du må markere innhold før du kan endre stil - Det er ingen aktive stiler eller formateringer på denne siden - Sett markøren til venstre i de 2 cellene du ønsker å slå sammen - Du kan ikke dele en celle som allerede er delt. - - - Om - Handling - Muligheter - Legg til - Alias - Er du sikker? - Ramme - av - Avbryt - Cellemargin - Velg - Lukk - Lukk vindu - Kommentar - Bekreft - Behold proposjoner - Fortsett - Kopier - Opprett - Database - Dato - Standard - Slett - Slettet - Sletter... - Design - Dimensjoner - Ned - Last ned - Rediger - Endret - Elementer - E-post - Feil - Finn - Høyde - Hjelp - Ikon - Importer - Indre margin - Sett inn - Installer - Justering - Språk - Layout - Laster - Låst - Logg inn - Logg ut - Logg ut - Makro - Flytt - Navn - Ny - Neste - Nei - av - OK - Åpne - eller - Passord - Sti - Plassholder ID - Ett øyeblikk... - Forrige - Egenskaper - E-post som innholdet i skjemaet skal sendes til - Papirkurv - Gjenværende - Gi nytt navn - Forny - Påkrevd - Prøv igjen - Rettigheter - Søk - Server - Vis - Hvilken side skal vises etter at skjemaet er sendt - Størrelse - Sorter - Send - Type - Søk... - Opp - Oppdater - Oppgrader - Last opp - Url - Bruker - Brukernavn - Verdi - Visning - Velkommen... - Bredde - Ja - Mappe - Søkeresultater - Sorter - Avslutt sortering - Eksempel - Bytt passord - til - Listevisning - Lagrer... - nåværende - Innbygging - Hent - valgt - - - Bakgrunnsfarge - Fet - Tekstfarge - Skrifttype - Tekst - - - Side - - - Installasjonsprogrammet kan ikke koble til databasen - Kunne ikke lagre Web.Config-filen. Vennligst endre databasens tilkoblingsstreng manuelt. - Din database er funnet og identifisert som - Databasekonfigurasjon - installer-knappen for å installere Umbraco %0% databasen]]> - Neste for å fortsette.]]> - Databasen ble ikke funnet! Vennligst sjekk at informasjonen i "connection string" i "web.config"-filen er korrekt.

For å fortsette, vennligst rediger "web.config"-filen (bruk Visual Studio eller din favoritteditor), rull ned til bunnen, og legg til tilkoblingsstrengen for din database i nøkkelen "umbracoDbDSN" og lagre filen.

Klikk prøv på nytt når du er ferdig.
Mer informasjon om redigering av web.config her.

]]>
- Vennligst kontakt din ISP om nødvendig. Hvis du installerer på en lokal maskin eller server, må du kanskje skaffe informasjonen fra din systemadministrator.]]> - Trykk på knappen oppgrader for å oppgradere databasen din til Umbraco %0%

Ikke vær urolig - intet innhold vil bli slettet og alt vil fortsette å virke etterpå!

]]>
- Trykk Neste for å fortsette.]]> - neste for å fortsette konfigurasjonsveiviseren]]> - Passordet til standardbrukeren må endres!]]> - Standardbrukeren har blitt deaktivert eller har ingen tilgang til Umbraco!

Ingen videre handling er nødvendig. Klikk neste for å fortsette.]]> - Passordet til standardbrukeren har blitt forandret etter installasjonen!

Ingen videre handling er nødvendig. Klikk Neste for å fortsette.]]> - Passordet er blitt endret! - Få en god start med våre introduksjonsvideoer - Ved å klikke på Neste-knappen (eller endre UmbracoConfigurationStatus i Web.config), godtar du lisensen for denne programvaren som angitt i boksen nedenfor. Legg merke til at denne Umbraco distribusjon består av to ulike lisenser, åpen kilde MIT lisens for rammen og Umbraco frivareverktøy lisens som dekker brukergrensesnittet. - Ikke installert. - Berørte filer og mapper - Mer informasjon om å sette opp rettigheter for Umbraco her - Du må gi ASP.NET brukeren rettigheter til å endre de følgende filer og mapper - Rettighetene er nesten perfekt satt opp!

Du kan kjøre Umbraco uten problemer, men du vil ikke være i stand til å installere de anbefalte pakkene for å utnytte Umbraco fullt ut.]]>
- Hvordan løse problemet - Klikk her for å lese tekstversjonen - innføringsvideo om å sette opp rettigheter for Umbraco eller les tekstversjonen.]]> - Rettighetsinnstillingene kan være et problem!

Du kan kjøre Umbraco uten problemer, men du vil ikke være i stand til å installere de anbefalte pakkene for å utnytte Umbraco fullt ut.]]>
- Rettighetsinstillingene er ikke klargjort for Umbraco!

For å kunne kjøre Umbraco, må du oppdatere rettighetsinnstillingene dine.]]>
- Rettighetsinnstillingene er perfekt!

Du er klar for å kjøre Umbraco og installere pakker!]]>
- Løser mappeproblem - Følg denne linken for mer informasjon om problemer med ASP.NET og oppretting av mapper - Konfigurerer mappetillatelser - - Jeg ønsker å starte fra bunnen. - lær hvordan) Du kan fortsatt velge å installere Runway senere. Vennligst gå til Utvikler-seksjonen og velg Pakker.]]> - Du har akkurat satt opp en ren Umbraco plattform. Hva vil du gjøre nå? - Runway er installert - Dette er vår liste av anbefalte moduler- Kryss av de du ønsker å installere, eller se denfulle listen av moduler ]]> - Bare anbefalt for erfarne brukere - Jeg vil starte med en enkel webside - "Runway" er en enkel webside som utstyrer deg med noen grunnleggende dokumenttyper og maler. Veiviseren kan sette opp Runway for deg automatisk, men du kan enkelt endre, utvide eller slette den. Runway er ikke nødvendig, og du kan enkelt bruke Umbraco uten den. Imidlertidig tilbyr Runway et enkelt fundament basert på de beste metodene for å hjelpe deg i gang fortere enn noensinne. Hvis du velger å installere Runway, kan du også velge blant grunnleggende byggeklosser kalt Runway Moduler for å forøke dine Runway-sider.

Sider inkludert i Runway: Hjemmeside, Komme-i-gang, Installere moduler.
Valgfrie Moduler: Toppnavigasjon, Sidekart, Kontakt, Galleri.
]]>
- Hva er Runway - Steg 1/5 Godta lisens - Steg 2/5 Database konfigurasjon - Steg 3/5: Valider filrettigheter - Steg 4/5: Skjekk Umbraco sikkerheten - Steg 5/5: Umbraco er klar for deg til å starte! - Tusen takk for at du valgte Umbraco! - Se ditt nye nettsted Du har installert Runway, hvorfor ikke se hvordan ditt nettsted ser ut.]]> - Mer hjelp og info Få hjelp fra vårt prisbelønte samfunn, bla gjennom dokumentasjonen eller se noen gratis videoer på hvordan man bygger et enkelt nettsted, hvordan bruke pakker og en rask guide til Umbraco terminologi]]> - Umbraco %0% er installert og klar til bruk - web.config filen, og oppdatere AppSetting-nøkkelen UmbracoConfigurationStatus til verdien '%0%']]> - starte øyeblikkelig ved å klikke på "Start Umbraco" knappen nedenfor.
Hvis du er ny på Umbraco, kan du finne mange ressurser på våre komme-i-gang sider.]]>
- Start Umbraco For å administrere din webside, åpne Umbraco og begynn å legge til innhold, oppdatere maler og stilark eller utvide funksjonaliteten]]> - Tilkobling til databasen mislyktes. - Umbraco Versjon 3 - Umbraco Versjon 4 - Se - Umbraco %0% for en ny installasjon eller oppgradering fra versjon 3.0.

Trykk "neste" for å starte veiviseren.]]>
- - - Språkkode - Språk - - - Du har vært inaktiv og vil logges ut automatisk om - Forny innlogging for å lagre - - - Da er det søndag! - Smil, det er mandag! - Hurra, det er tirsdag! - For en herlig onsdag! - Gledelig torsdag! - Endelig fredag! - Gledelig lørdag - Logg på nedenfor - Logg på med - Din sesjon er utløpt - © 2001 - %0%
umbraco.com

]]>
- - - Skrivebord - Seksjoner - Innhold - - - Velg side over... - %0% er nå kopiert til %1% - Kopier til - %0% er nå flyttet til %1% - Flytt til - har blitt valgt som rot til ditt nye innhold, klikk 'ok' nedenfor. - Ingen node er valgt, vennligst velg en node i listen over før du klikker 'fortsett' - Gjeldende nodes type tillates ikke under valgt node - Gjeldende node kan ikke legges under en underordnet node - Denne noden kan ikke ligge på rotnivå - Handlingen tillates ikke. Du mangler tilgang til en eller flere underordnede noder. - Relater kopierte elementer til original(e) - - - Rediger dine varsler for %0% - - Hei %0%

- -

Dette er en automatisk mail for å informere om at handlingen '%1%' - er blitt utført på siden '%2%' - av brukeren '%3%' -

- -

-

Rettelser:

- - %6% -
-

- - - -

Ha en fin dag!

- Vennlig hilsen Umbraco roboten -

]]>
- [%0%] Varsling om %1% utført på %2% - Varslinger - - - Umbraco-pakker har vanligvis endelsen ".umb" eller ".zip".]]> - Utvikler - Demonstrasjon - Dokumentasjon - Metadata - Pakkenavn - Pakken inneholder ingen elementer -
Du kan trygt fjerne pakken fra systemet ved å klikke "avinstaller pakke" nedenfor.]]>
- Ingen oppdateringer tilgjengelig - Alternativer for pakke - Lesmeg for pakke - Pakkebrønn - Bekreft avinstallering - Pakken ble avinstallert - Pakken ble vellykket avinstallert - Avinstaller pakke - Advarsel: alle dokumenter, media, etc. som som er avhengig av elementene du sletter, vil slutte å virke, noe som kan føre til ustabilitet, så avinstaller med forsiktighet. Hvis du er i tvil, kontakt pakkeutvikleren.]]> - Last ned oppdatering fra pakkeregisteret - Oppgrader pakke - Oppgraderingsinstrukser - Det er en oppdatering tilgjengelig for denne pakken. Du kan laste den ned direkte fra pakkebrønnen. - Pakkeversjon - Pakkeversjonshistorie - Se pakkens nettsted - - - Lim inn med full formattering (Anbefales ikke) - Teksten du er i ferd med å lime inn, inneholder spesialtegn eller formattering. Dette kan skyldes at du kopierer fra f.eks. Microsoft Word. Umbraco kan fjerne denne spesialformatteringen automatisk slik at innholdet er mer velegnet for visning på en webside. - Lim inn som ren tekst, dvs. fjern al formattering - Lim inn og fjern uegnet formatering (anbefalt) - - - Avansert: Beskytt ved å velge hvilke brukergrupper som har tilgang til siden - ved å bruke Umbraco's medlems-grupper]]> - Du må opprette en medlemsgruppe før du kan bruke rollebasert autentikasjon. - Feilside - Brukt når personer logger på, men ikke har tilgang - Hvordan vil du beskytte siden din? - %0% er nå beskyttet - Beskyttelse fjernet fra %0% - Innloggingsside - Velg siden som har loginformularet - Fjern beskyttelse - Velg sidene som inneholder login-skjema og feilmelding ved feil innolgging. - Velg rollene som har tilgang til denne siden - Sett brukernavn og passord for denne siden - Enkelt: Beskytt ved hjelp av brukernavn og passord - Om du ønsker å bruke enkel autentisering via ett enkelt brukernavn og passord - - - %0% kunne ikke publiseres fordi den har planlagt utgivelsesdato. - %0% ble ikke publisert. Ett eller flere felter ble ikke godkjent av validering. - %0% kunne ikke publiseres fordi et tredjepartstillegg avbrøt handlingen. - %0% kan ikke publiseres fordi en overordnet side ikke er publisert. - Inkluder upubliserte undersider - Publiserer - vennligst vent... - %0% av %1% sider har blitt publisert... - %0% er nå publisert - %0% og alle undersider er nå publisert - Publiser alle undersider - ok for å publisere %0% og dermed gjøre innholdet synlig for alle.

Du kan publisere denne siden og alle dens undersider ved å krysse av Publiser alle undersider nedenfor.]]>
- - - Du har ikke konfigurert noen godkjente farger - - - skriv inn ekstern lenke - velg en intern side - Tittel - Lenke - Åpne i nytt vindu - Skriv inn en tekst - Skriv inn en lenke - - - Nullstill - - - Gjeldende versjon - Rød tekst vil ikke bli vist i den valgte versjonen. , grønn betyr lagt til]]> - Dokumentet er tilbakeført til en tidligere versjon - Dette viser den valgte versjonen som HTML, bruk avviksvisningen hvis du ønsker å se forksjellene mellom to versjoner samtidig. - Tilbakefør til - Velg versjon - Vis - - - Rediger scriptfilen - - - Concierge - Innhold - Courier - Utvikler - Umbraco konfigurasjonsveiviser - Mediaarkiv - Medlemmer - Nyhetsbrev - Innstillinger - Statistikk - Oversettelse - Brukere - Hjelp - Skjemaer - - - De beste Umbraco opplæringsvideoer - - - Standardmal - Ordboksnøkkel - For å importere en dokumenttype, finn ".udt" filen på datamaskinen din ved å klikke "Utforsk" knappen og klikk "Importer" (du vil bli spurt om bekreftelse i det neste skjermbildet) - Ny tittel på arkfane - Nodetype - Type - Stilark - Script - Stilark-egenskap - Arkfane - Tittel på arkfane - Arkfaner - Hovedinnholdstype aktivert - Denne dokumenttypen bruker - som hoveddokumenttype. Arkfaner fra hoveddokumenttyper vises ikke og kan kun endres på hoveddokumenttypen selv. - Ingen egenskaper definert i denne arkfanen. Klikk på "legg til ny egenskap" lenken i toppen for å opprette en ny egenskap. - - - Sort order - Creation date - Sortering ferdig. - Dra elementene opp eller ned for å arrangere dem. Du kan også klikke kolonneoverskriftene for å sortere alt på en gang. - - - - En feil oppsto - Utilstrekkelige brukertillatelser, kunne ikke fullføre operasjonen - Avbrutt - Handlingen ble avbrutt av et tredjepartstillegg - Publisering ble avbrutt av et tredjepartstillegg - Egenskaptypen finnes allerede - Egenskapstype opprettet - DataType: %1%]]> - Egenskapstype slettet - Innholdstype lagret - Du har opprettet en arkfane - Arkfane slettet - Arkfane med id: %0% slettet - Stilarket ble ikke lagret - Stilarket ble lagret - Stilark lagret uten feil - Datatype lagret - Ordbokelement lagret - Publiseringen feilet fordi den overliggende siden ikke er publisert - Innhold publisert - og er nå synlig for besøkende - Innhold lagret - Husk å publisere for å gjøre endringene synlig for besøkende - Sendt for godkjenning - Endringer har blitt sendt til godkjenning - Media lagret - Media lagret uten feil - Medlem lagret - Stilarksegenskap lagret - Stilark lagret - Mal lagret - Feil ved lagring av bruker (sjekk loggen) - Bruker lagret - Brukertypen lagret - Filen ble ikke lagret - Filen kunne ikke lagres. Vennligst sjekk filrettigheter - Filen ble lagret - Filen ble lagret uten feil - Språk lagret - Malen ble ikke lagret - Vennligst forviss deg om at du ikke har to maler med samme alias - Malen ble lagret - Malen ble lagret uten feil! - Innhold avpublisert - Delmal lagret - Delmal lagret uten feil - Delmal ble ikke lagret! - En feil oppsto ved lagring av delmal - - - Bruk CSS syntaks f.eks: h1, .redHeader, .blueText - Rediger stilark - Rediger egenskap for stilark - Navn for å identifisere stilarksegenskapen i rik-tekst editoren - Forhåndsvis - Stiler - - - Rediger mal - Sett inn innholdsområde - Sett inn plassholder for innholdsområde - Sett inn ordbokselement - Sett inn makro - Sett inn Umbraco sidefelt - Hovedmal - Hurtigguide til Umbraco sine maltagger - Mal - - - Image - Macro - Sett inn element - Velg layout - Legg til rad - Legg til innhold - Slipp innhold - Raden har tilpasset design - Innholdstypen er ikke tillatt her - Innholdstypen er tillatt her - Klikk for å bygge inn - Klikk for å sette inn et bilde - Bildetekst... - Skriv her... - Rutenettoppsett - Et oppsett er det overordnede arbeidsområdet til ditt rutenett - du vil typisk kun behøve ett eller to - Legg til rutenettoppsett - Juster oppsettet ved å konfigurere kolonnebredder og legge til ytterligere seksjoner - Radkonfigurasjoner - Rader er forhåndsdefinerte celler arrangert vannrett - Legg til radkonfigurasjon - Juster raden ved å sette cellebredder og legge til flere celler - Kolonner - Totalt antall kolonner i rutenettet - Innstillinger - Konfigurer hvilke innstillinger brukeren kan endre - Stiler - Konfigurer hvilke stiler redaktørene kan endre - Tillatt alle editorer - Tillat alle radkonfigurasjoner - Bruk som standard - Velg ekstra - Velg standard - er lagt til - - - Alternativt felt - Alternativ tekst - Store/små bokstaver - Encoding - Felt som skal settes inn - Konverter linjeskift - Erstatter et linjeskift med htmltaggen <br> - Egendefinerte felt - Ja, kun dato - Formatter som dato - HTML koding - Formater spesialtegn med tilsvarende HTML-tegn. - Denne teksten vil settes inn etter verdien av feltet - Denne teksten vil settes inn før verdien av feltet - Små bokstaver - Ingen - Sett inn etter felt - Sett inn før felt - Rekursivt - Standardfelter - Store bokstaver - URL koding - Dersom innholdet av feltene skal sendes til en URL skal spesialtegn formatteres - Denne teksten vil benyttes dersom feltene over er tomme - Dette feltet vil benyttes dersom feltet over er tomt - Ja, med klokkeslett. Dato/tid separator: - - - Oversettelses detaljer - Last ned XML DTD - Felt - Inkluder undersider - - Ingen oversettelses-bruker funnet. Vennligst opprett en oversettelses-bruker før du begynner å sende innhold til oversetting - Siden '%0%' har blitt sendt til oversetting - Send til oversetting - Antall ord - Oversett til - Oversetting fullført. - Du kan forhåndsvise sidene du nettopp har oversatt ved å klikke nedenfor. Hvis den originale siden finnes, vil du få en sammenligning av sidene. - Oversetting mislykkes, XML filen kan være korrupt - Alternativer for oversetting - Oversetter - Last opp XML med oversettelse - - - Hurtigbufferleser - Papirkurv - Opprettede pakker - Datatyper - Ordbok - Installerte pakker - Installer utseende - Installer startpakke - Språk - Installer lokal pakke - Makroer - Mediatyper - Medlemmer - Medlemsgrupper - Roller - Medlemstyper - Dokumenttyper - Pakker - Pakker - Installer fra pakkeregister - Installer Runway - Runway moduler - Skriptfiler - Skript - Stiler - Maler - Brukertillatelser - Brukertyper typer - Brukere - - - Ny oppdatering er klar - %0% er klar, klikk her for å laste ned - Ingen forbindelse til server - Kunne ikke sjekke etter ny oppdatering. Se trace for mere info. - - - Administrator - Kategorifelt - Bytt passord - Nytt passord - Bekreft nytt passord - Du kan endre passordet til Umbraco ved å fylle ut skjemaet under og klikke "Bytt passord" knappen. - Innholdskanal - Beskrivelsesfelt - Deaktiver bruker - Dokumenttype - Redaktør - Utdragsfelt - Språk - Brukernavn - Øverste nivå i Media - Moduler - Deaktiver tilgang til Umbraco - Passord - Nullstill passord - Passordet er endret - Bekreft nytt passord - Nytt passord - Nytt passord kan ikke være blankt - Gjeldende passord - Feil passord - Nytt og bekreftet passord må være like - Nytt og bekreftet passord må være like - Overskriv tillatelser på undernoder - Du redigerer for øyeblikket tillatelser for sidene: - Velg sider for å redigere deres tillatelser - Søk i alle undersider - Startnode - Navn - Brukertillatelser - Forfatter - Endre - Din profil - Din historikk - Sesjonen utløper om - -
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml b/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml deleted file mode 100644 index 0a87631329..0000000000 --- a/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml +++ /dev/null @@ -1,1269 +0,0 @@ - - - - The Umbraco community - http://our.umbraco.org/documentation/Extending-Umbraco/Language-Files - - - 管理主機名稱 - 跟蹤審計 - 流覽節點 - 改變文檔類型 - 複製 - 創建 - 創建擴展包 - 刪除 - 禁用 - 清空回收站 - 匯出文檔類型 - 導入文檔類型 - 導入擴展包 - 即時編輯模式 - 退出 - 移動 - 提醒 - 公眾存取權限 - 發佈 - 取消發佈 - 重新載入節點 - 重新發佈整站 - 回復 - 許可權 - 回滾 - 提交至發佈者 - 發送給翻譯 - 排序 - 提交至發佈者 - 翻譯 - 更新 - 預設值 - - - 禁止訪問 - 添加功能變數名稱 - 移除 - 錯誤的節點 - 功能變數名稱錯誤 - 功能變數名稱重複 - 語言 - 功能變數名稱 - 新功能變數名稱 '%0%' 已創建 - 功能變數名稱 '%0%' 已刪除 - 功能變數名稱 '%0%' 已使用 - 功能變數名稱 '%0%' 已更新 - 編輯當前功能變數名稱 - - 繼承 - 語言 - 或從父節點繼承文化設定。
- 也會改變目前節點設定,除非下方網域有其他項目。]]>
- 功能變數名稱 - - - 查看 - - - 清除選擇 - 選擇 - 做別的事情 - 粗體 - 取消段落縮進 - 插入表單字段 - 插入圖片標題 - 編輯Html - 段落縮進 - 斜體 - 居中 - 左對齊 - 右對齊 - 插入連結 - 插入本地連結(錨點) - 圓點列表 - 數字清單 - 插入巨集 - 插入圖片 - 編輯關聯 - 回到清單 - 保存 - 保存並發佈 - 保存並提交審核 - 保存清單檢視 - 預覽 - 因未設置範本無法預覽 - 選擇樣式 - 顯示樣式 - 插入表格 - - - 要更改所選節點的文檔類型,先在列表中選擇合適的文檔類型。 - 然後設置當前文檔類型到新文檔類型的各欄位間的對應映射關係並保存。 - 內容已被重新發佈 - 當前屬性 - 當前類型 - 不能改變文檔類型,因為沒有可替代的類型。 - 文檔類型已更改 - 要映射的欄位 - 映射欄位 - 新範本 - 新類型 - - 內容 - 選擇新的文檔類型 - 選中文檔的類型已被成功更改為[new type],以下欄位被映射: - - 不能完成欄位映射,因為存在一個欄位映射至多欄位的問題。 - 僅顯示可作為替代的文檔類型。 - - - 已發表 - 關於本頁 - 別名 - (圖片的替代文本) - 替代連結 - 點擊編輯 - 創建者 - 創建者 - 更新者 - 創建時間 - 此文件創建的日期時間 - 文檔類型 - 編輯 - 過期於 - 該項發佈之後有更改 - 該項沒有發佈 - 最近發佈 - 沒有可供顯示的項目 - 此列表中沒有可供顯示的項目 - 媒體類型 - 媒體連結位址 - 會員組 - 角色 - 會員類型 - 沒有選擇時間 - 頁標題 - 屬性 - 該文檔不可見,因為其上級 '%0%' 未發佈。 - 糟糕:該文檔已發佈,但是沒有更新至緩存(內部錯誤) - 糟糕:沒辦法連結到此網址(內部錯誤-請參見記錄) - 糟糕:此文件已經發表,但是網址和其他內容相衝 %0% - 發佈 - 發佈狀態 - 發佈於 - 取消發表於 - 清空時間 - 排序完成 - 拖拽項目或按一下列頭即可排序,可以按住Shift多選。 - 統計 - 標題(可選) - 其他說明文字(可選) - 類型 - 取消發佈 - 最近編輯 - 本文件修改時間 - 移除文件 - 連結到文檔 - 會員組成員 - 非會員組成員 - 子項目 - 目標 - 預計發表的時間(伺服器端) - 這是什麼意思?]]> - - - 點選以便上傳 - 或按這裡選擇檔案 - 檔案大小上限為 - - - 新增一位會員 - 所有會員 - - - 您想在哪裡創建 %0% - 創建在 - 選擇類型和標題 - "文檔類型"處變更。]]> - "媒體類型"處變更。]]> - 文檔類型沒有相關範本 - 沒有資料夾 - 新資料類別 - - - 流覽您的網站 - - 隱藏 - 如果Umbraco沒有打開,您可能需要允許彈出式視窗。 - 已經在新視窗中打開 - 重啟 - 訪問 - 歡迎 - - - 留下 - 放棄變更 - 您有未存檔的變更 - 您確定要離開本頁? - 您有未存檔的變更 - - - 完成 - 刪除 %0% 個項目 - 刪除 %0% 個項目 - 刪除 %1% 個中的 %0% 個項目 - 刪除 %1% 個中的 %0% 個項目 - 已發佈 %0% 個項目 - 已發佈 %0% 個項目 - 已發佈 %1% 個中的 %0% 個項目 - 已發佈 %1% 個中的 %0% 個項目 - 取消發佈 %0% 個項目 - 取消發佈 %0% 個項目 - 取消發佈 %1 個中的 %0% 個項目 - 取消發佈 %1 個中的 %0% 個項目 - 移動 %0% 個項目 - 移動 %0% 個項目 - 移動 %1 個中的 %0% 個項目 - 移動 %1 個中的 %0% 個項目 - 複製 %0% 個項目 - 複製 %0% 個項目 - 複製 %1 個中的 %0% 個項目 - 複製 %1 個中的 %0% 個項目 - - - 錨點名稱 - 管理主機名稱 - 關閉窗口 - 您確定要刪除嗎 - 您確定要禁用嗎 - 您確定嗎? - 您確定嗎? - 剪切 - 編輯字典項 - 編輯語言 - 插入本地連結 - 插入字元 - 插入圖片標題 - 插入圖片 - 插入連結 - 插入巨集 - 插入表格 - 最近編輯 - 連結 - 內部連結: - 本地連結請用“#”號開頭 - 在新視窗中打開? - 巨集設置 - 本巨集沒有包含您可以編輯的屬性 - 粘貼 - 編輯許可權 - 正在清空回收站,請不要關閉窗口。 - 回收站已清空 - 從回收站刪除的項目將不可恢復 - regexlib.com的網站服務目前出現些狀況,而我們無能為力。我們對此不便感到十分抱歉。]]> - 查找規則運算式來驗證輸入,如: 'email、'zip-code'、'url'。 - 移除巨集 - 必填項目 - 網站已重建索引 - 網站緩存已刷新,所有已發佈的內容更新生效。 - 網站緩存將會刷新,所有已發佈的內容將會更新。 - 表格列數 - 表格行數 - 設定預留位置代碼 以便您要在子範本中插入內容到本範本時,填入此代碼到 <asp:content /> 裡面。]]> - 選擇預留位置代碼 於此清單中。您只能選擇目前父範本中的代碼。]]> - 點擊圖片查看完整大小 - 拾取項 - 查看緩存項 - 與原本相關 - 最友善的社群 - 頁面連結 - 打開此連結文檔至新視窗或標籤頁 - 媒體連結 - 選擇媒體 - 選擇圖示 - 選擇項目 - 選擇連結 - 選擇巨集 - 選擇內容 - 選擇會員 - 選擇會員群組 - 沒有找到任何圖示 - 本巨集沒有需要參數 - 外部登入提供者 - 例外細節 - 詳細記錄 - 內部例外 - 連結您的 - 取消連結您的 - 帳戶 - 選擇編輯器 - - - %0%' 編輯不同語言版本,
您可以在左方選單「語言」中增添新的語言 - ]]>
- 語言名稱 - - - 輸入您的使用者名稱 - 輸入您的密碼 - 確認您的密碼 - 命名此 %0%... - 輸入一個名稱 - 標籤... - 輸入一段描述... - 搜尋請輸入... - 過濾請輸入... - 增加標籤(每個標籤後請按輸入鍵)... - 輸入您的電子郵件 - - - 允許子項節點類型 - 創建 - 刪除選項卡 - 描述 - 新建選項卡 - 選項卡 - 縮略圖 - 新增自訂清單檢視 - 移除自訂清單檢視 - - - 添加預設值 - 資料庫資料類型 - 資料類型唯一標識 - 渲染控制項 - 按鈕 - 允許高級設置 - 允許快顯功能表 - 插入圖片預設最大 - 關聯的樣式表 - 顯示標籤 - 寬和高 - - - 資料已保存,但是發佈前您需要修正一些錯誤: - 當前成員提供程式不支援修改密碼(EnablePasswordRetrieval的值應該為true) - %0% 已存在 - 發現錯誤: - 發現錯誤: - 密碼最少%0%位元,且至少包含%1%位元非字母數位記號 - %0% 必須是整數 - %1% 中的 %0% 欄位是必填項 - %0% 是必填項 - %1% 中的 %0% 格式不正確 - %0% 格式不正確 - - - 收到伺服器傳來的錯誤 - 該檔案類型已被管理員禁用 - 注意,儘管配置中允許CodeMirror,但是它在IE上不夠穩定,所以無法在IE運行。 - 請為新的屬性類型填寫名稱和別名! - 許可權有問題,訪問指定文檔或資料夾失敗! - 讀取片段視圖腳本錯誤(檔案:%0%) - 讀取使用者控制項 %0% 錯誤 - 請輸入標題 - 請選擇類型 - 圖片尺寸大於原始尺寸不會提高圖片品質,您確定要把圖片尺寸變大嗎? - 預設打開頁面不存在,請聯繫管理員 - 請先選擇內容,再設置樣式。 - 沒有可用的樣式 - 請把游標放在您要合併的兩個儲存格中的左邊儲存格 - 非合併儲存格不能分離。 - - - 關於 - 操作 - 操作 - 添加 - 別名 - 所有 - 您確定嗎? - 回去 - 邊框 - - 取消 - 儲存格邊距 - 選擇 - 關閉 - 關閉窗口 - 備註 - 確認 - 強制屬性 - 繼續 - 複製 - 創建 - 資料庫 - 時間 - 默認 - 刪除 - 已刪除 - 正在刪除… - 設計 - 規格 - - 下載 - 編輯 - 已編輯 - 元素 - 郵箱 - 錯誤 - 查找文檔 - - 幫助 - 圖示 - 導入 - 內邊距 - 插入 - 安裝 - 不合格 - 對齊 - 語言 - 佈局 - 載入中 - 鎖定 - 登入 - 退出 - 登出 - 巨集 - 必要 - 移動 - 名稱 - 新的 - 下一步 - - 屬於 - 確定 - 打開 - - 密碼 - 路徑 - 預留位置代碼 - 請稍候… - 上一步 - 屬性 - 接收資料郵箱 - 回收站 - 保持狀態中 - 重命名 - 更新 - 必要 - 重試 - 許可權 - 搜索 - 伺服器 - 顯示 - 在發送時預覽 - 大小 - 排序 - 送出 - 類型 - 輸入內容開始搜尋… - - 更新 - 更新 - 上傳 - 連結位址 - 用戶 - 用戶名 - - 查看 - 歡迎… - - - 資料夾 - 搜尋結果 - 重新排列 - 我已經完成排列 - 預覽 - 更改密碼 - - 清單檢視 - 存檔中... - 目前 - 內嵌 - 選取的 - - - - - - 增加標籤頁 - 增加屬性 - 增加編輯器 - 增加範本 - 增加子節點 - 增加子項目 - 編輯資料類別 - 瀏覽區塊 - 捷徑 - 顯示捷徑 - 開關清單檢視 - 開關是否允許為根項目 - - - 背景色 - 粗體 - 前景色 - 字體 - 文本 - - - 頁面 - - - 無法連接到資料庫。 - 無法保存web.config檔,請手工修改。 - 發現資料庫 - 資料庫配置 - 安裝 按鈕來安裝Umbraco資料庫 %0% - ]]> - 下一步繼續。]]> - 沒有找到資料庫!請確認檔案"web.config"中的字串"connection string"是否正確。

-

請編輯檔案"web.config" (例如使用Visual Studio或您喜歡的編輯器),移動到檔案底部,並在名稱為"UmbracoDbDSN"的字串中設定資料庫連結資訊,並存檔。

-

- 點選重試按鈕當上述步驟完成。
- - 在此查詢更多編輯web.config的資訊。

]]>
- - 若需要時,請聯繫您的網路公司。如果您在本地機器或伺服器安裝的話,您也許需要聯絡系統管理者。]]> - - 點選升級按鈕來升級Umbraco資料庫 %0%

-

- 請別擔心 - 不會刪除任何資料而且馬上就會繼續運作! -

- ]]>
- 點選下一步繼續。]]> - 下一步繼續設定精靈。]]> - 預設使用者的密碼必須更改!]]> - 預設使用者已經被暫停或沒有Umbraco的使用權!

不需更多的操作步驟。點選下一步繼續。]]> - 安裝後預設使用者的密碼已經成功修改!

不需更多的操作步驟。點選下一步繼續。]]> - 密碼已更改 - 作為入門者,從視頻教程開始吧! - 點擊下一步 (或在Web.config中自行修改UmbracoConfigurationStatus),意味著您接受上述授權合約。 - 安裝失敗。 - 受影響的檔和資料夾 - 此處查看更多資訊 - 您需要對以下檔和資料夾授於ASP.NET用戶修改許可權 - 您的權限設定幾近完美!

- 您可以正常執行Umbraco沒有任何問題,只差您將沒有辦法安裝那些建議需要全部許可權的插件。]]>
- 如何解決 - 點擊閱讀文字版 - 影片教學來瞭解如何設定Umbraco的資料夾權限或閱讀文字版本。]]> - 您的權限可能有點小問題! -

- 您可以正常執行Umbraco沒有任何問題,然而您將無法新增資料夾或安裝那些可以讓Umbraco發揮全力的插件。]]>
- 您的權限設定尚未未完成! -

- 您需要更新權限設定才能執行Umbraco。]]>
- 您的權限設定完美無瑕!

- 您已經準備好執行Umbraco和安裝插件!]]>
- 解決資料夾問題 - 點此查看ASP.NET和創建資料夾的問題解決方案 - 設置資料夾許可權 - - 我要從頭開始 - 學習該怎麼做) - 您晚點仍可以選擇安裝Runway,請至開發者區域選擇安裝。 - ]]> - 您剛剛安裝了一個乾淨的系統,要繼續嗎? - “Runway”已安裝 - - 這是我們的模組推薦清單,選取您想要安裝的項目,或者至 查詢完整清單。 - ]]> - 僅推薦高級用戶使用 - 給我一個簡單的網站 - - "Runway"是一個提供基本檔案類別和範本的簡單網站。安裝程式會自動幫您設定Runway, - 但你仍可輕易編輯,擴充或移除它。它並非必要項目而且您可以在沒它的情況下完美執行Umbraco。然而, - Runway提供一個輕鬆簡便但基於寶貴經驗的平台讓您可以更快開始。 - 如果您安裝Runway,您還可以選擇名為「Runway模組」的基本區塊來加強Runway頁面。 -

- - 內含於Runway: 首頁,準備開始頁面,模組安裝頁面。
- 可選模組: 上方瀏覽列,網站地圖,聯絡,藝廊。 -
- ]]>
- “Runway”是什麼? - 步驟 1/5:接受授權合約 - 步驟 2/5:資料庫配置 - 步驟 3/5:文件許可權驗證 - 步驟 4/5:系統安全性 - 步驟 5/5:一切就緒,可以開始使用系統。 - 感謝選擇我們的產品 - 參觀您的新網站 -您剛安裝好Runway,何不瞧瞧它的模樣。]]> - 更多的幫忙與資訊 -從我們獲獎的社群得到幫助,瀏覽文件,或觀看免費影片來瞭解如何輕鬆架設網站,如何使用插件,和瞭解Umbraco項目名稱的快速上手指引。]]> - 系統 %0% 安裝完畢 - /web.config 檔案並且更新AppSetting中的字串UmbracoConfigurationStatus 內容為 '%0%'。]]> - 快速開始指引。
如果您是Umbraco的新成員, -您可以在其中找到相當多的資源。]]>
- 啟動Umbraco -想要管理您的網站時,只需開啟Umbraco後台便可增加內容,更新範本和樣式表,或增添新功能。]]> - 無法連接到資料庫。 - 系統版本 3 - 系統版本 4 - 觀看 -
- 點選"下一步"來啟動精靈。]]>
- - - 語言代碼 - 語言名稱 - - - 使用者在空閒狀態下將會自動登出 - 已更新,繼續工作。 - - - 超級星期天快樂 - 瘋狂星期一快樂 - 熱鬧星期二快樂 - 美妙星期三快樂 - 悅耳星期四快樂 - 時髦星期五快樂 - 喵喵星期六快樂 - 下方登入 - 登入使用 - 連線時間過了 - © 2001 - %0%
Umbraco.com

]]>
- 忘記密碼? - 一封內有重設密碼連結的電子郵件已經寄出給您 - 一封內有重設密碼連結的電子郵件已經寄到此信箱 - 回到登入畫面 - 請輸入新密碼 - 您的密碼已經更新 - 您點選的連結是無效或過期的 - Umbraco:重設密碼 - 您登入到後台的使用者名稱是:%0%

點選這裡來重設您的密碼或將此連結複製/貼上到您的瀏覽器:

%1%

]]>
- - - 儀錶板 - 區域 - 內容 - - - 選擇上面的頁面… - %0% 被複製到 %1% - 將 %0% 複製到 - %0% 已被移動到 %1% - 將 %0% 移動到 - 作為內容的根結點,點“確定”。 - 尚未選擇節點,請選擇一個節點點擊“確定”。 - 類型不符不允許選擇 - 該項不能移到其子項 - 當前節點不能建在根節點下 - 您在子項的許可權不夠,不允許該操作。 - 複本和原本建立關聯 - - - 為 %0% 編寫通知 - - 哈嘍 %0%

- -

這是一封自動產生的信件來通知您 %1% 工作 - 已經在頁面 %2% 上由使用者 %3% 執行完成 -

- -

-

更新摘要:

- - %6% -
-

- - - -

祝您有美好的一天!

- Umbraco機器人 謹上 -

]]>
- 在 %2%,[%0%] 關於 %1% 的通告已執行。 - 通知 - - - - 按鈕並點選該檔案。Umbraco擴展包通常有「.zip」的副檔名。 - ]]> - 作者 - 演示 - 文檔 - 中繼資料 - 名稱 - 擴展包不含任何項 -
- 您可以點選下方「移除擴展包」來安全地移除此項目。]]>
- 無可用更新 - 選項 - 說明 - 程式庫 - 確認卸載 - 已卸載 - 擴展包卸載成功 - 卸載 - - 注意: 任何文檔,媒體或需要這些項目才能運作的物件將會停止運作,並可能使得系統不穩定, - 請小心移除。若有疑慮,請聯絡擴展包作者。]]> - 從程式庫下載更新 - 更新擴展包 - 更新說明 - 擴展包有可用的更新,您可以從程式庫網站更新。 - 版本 - 版本歷史 - 訪問擴展包網站 - 擴展包已安裝 - 這個擴展包無法安裝,它需要Umbraco至少是版本 %0% - 移除中... - 下載中... - 匯入中... - 安裝中... - 重新啟動中,請稍後... - 都好了,您的瀏覽器將重新整理,請稍待... - - - 帶格式粘貼(不推薦) - 您所粘貼的文本含有特殊字元或格式,Umbraco將清除以適應網頁。 - 無格式粘貼 - 粘貼並移除格式(推薦) - - - 基於角色的保護 - 請使用Umbraco的會員群組。]]> - 使用基於角色的授權需要首先建立會員組。 - 錯誤頁 - 當用戶登錄後訪問沒有許可權的頁時顯示該頁 - 選擇限制訪問此頁的方式 - %0% 現在處於受保護狀態 - %0% 的保護被取消 - 登錄頁 - 選擇公開的登錄入口 - 取消保護 - 選擇一個包含登錄表單和提示資訊的頁 - 選擇訪問該頁的角色類型 - 為此頁設置帳號和密碼 - 單用戶保護 - 如果您只希望提供一個用戶名和密碼就能訪問 - - - - - - - - 包含未發佈的子項 - 正在發佈,請稍候… - %0% 中的 %1% 頁面已發佈… - %0% 已發佈 - %0% 及其子項已發佈 - 發佈 %0% 及其子項 - 發佈按鈕來將%0%的內容設定為公開。

- 您可以同時發佈本頁以及其子項目若您點選下面的包含子頁。 - ]]>
- - - 您尚未設定任何許可顏色 - - - 輸入外部連結 - 選擇內部連結 - 標題 - 連結 - 新視窗 - 輸入新標題 - 輸入連結 - - - 重設 - - - 當前版本 - 紅色 文字將不會顯示於所選版本,而綠色表示增加部分。]]> - 文檔已回滾 - 這顯示所選版本的HTML格式,如果您想要比較兩版本的差異,請使用比較檢視 - 回滾至 - 選擇版本 - 查看 - - - 編輯腳本 - - - Concierge - 內容 - Courier - 開發 - 設定精靈 - 媒體 - 會員 - 消息 - 設置 - 統計 - 翻譯 - 用戶 - 說明 - 表單 - - - 最好的Umbraco影片教學 - - - 預設範本 - 字典鍵 - 要導入文檔類型,請點擊“流覽”按鈕,再點擊“導入”,然後在您電腦上查找 ".udt"檔導入(下一頁中需要您再次確認) - 新建選項卡標題 - 節點類型 - 類型 - 樣式表 - 腳本 - 樣式表屬性 - 選項卡 - 選項卡標題 - 選項卡 - 主控文件類型啟動 - 該文檔類型使用 - 作為主控文件類型. 主控文件類型的標籤只能在主控文件類型裡修改。 - 沒有欄位設置在該標籤頁 - 增加圖示 - - - 排列順序 - 增添時間 - 排序完成。 - 上下拖拽項目或按一下列頭進行排序 - - - - 驗證 - 驗證錯誤一定要修正才能儲存項目 - 失敗 - 使用者權限不足,無法完成操作 - 已取消 - 操作被協力廠商外掛程式取消 - 發佈被協力廠商外掛程式取消 - 屬性類型已存在 - 屬性類型已創建 - 資料類別:%1%]]> - 屬性類型已刪除 - 內容類別型已保存 - 選項卡已創建 - 選項卡已刪除 - id為%0%的選項卡已刪除 - 樣式表未保存 - 樣式表已保存 - 樣式表保存,無錯誤。 - 資料類型已保存 - 字典項已保存 - 因為上級頁面未發佈導致發佈失敗! - 內容已發佈 - 公眾可見 - 內容已保存 - 請發佈以使更改生效 - 提交審核 - 更改已提交審核 - 媒體已保存 - 媒體已保存 - 會員已保存 - 樣式表屬性已保存 - 樣式表已保存 - 範本已保存 - 保存使用者出錯(請查看日誌) - 用戶已保存 - 用戶類型已保存 - 檔未保存 - 檔無法保存,請檢查許可權。 - 檔保存 - 檔保存,無錯誤。 - 語言已保存 - 媒體類別已儲存 - 會員類別已儲存 - 範本未保存 - 範本別名相同 - 範本已保存 - 範本保存,無錯誤。 - 內容已取消發佈 - 片段視圖已保存 - 片段視圖保存,無錯誤。 - 片段視圖未保存 - 片段視圖因為錯誤未能保存 - - - 使用CSS語法,如:h1、.redHeader、.blueTex。 - 編輯樣式表 - 編輯樣式屬性 - 編輯器中的樣式屬性名 - 預覽 - 樣式 - - - 編輯範本 - 插入內容區 - 插入內容預留位置 - 插入字典項 - 插入巨集 - 插入頁欄位 - 母版 - 範本標籤快速指南 - 範本 - - - Image - Macro - 選擇內容類別 - 選擇排列方式 - 新增一行 - 新增內容 - 放棄內容 - 設定已儲存 - 此處不允許有內容 - 此處允許有內容 - 點選來內嵌 - 點選來插入圖片 - 圖片標題... - 在此填寫... - 網格排列方式 - 排列是指網格編輯器的整體工作區域,通常您只需要一種或兩種排列方式 - 增加網格排列方式 - 藉由設定列寬以及增加新的區域來調整排列方式 - 行設定 - 行是預先水平排列的格子 - 增加行設定 - 藉由設定小格寬度和增添小格來調整此行 - - 網格排列方式的列總數 - 設定 - 調整設定編輯器可以改變的項目 - 樣式 - 調整樣式編輯器可以改變的項目 - 允許所有編輯器 - 允許所有行設定 - 定為預設 - 選擇額外 - 選擇預設 - 已增加 - - - 組合 - 您沒有增加任何選項卡 - 繼承的表格 - 增加屬性 - 必要標籤 - 允許清單檢視 - 允許內容項目顯示成可以排列及搜尋的清單,子項目不會被顯示 - 允許的範本 - 選擇哪些範本編輯器可以使用於此類別的內容 - 允許為根項目 - 允許編輯器新增此類別的內容為根項目 - 允許子節點種類 - 允許某些特定種類能夠成為此種類內容的子項目 - 選擇子節點 - 從已存在的文檔類別中繼承選項卡以及屬性。新選項卡將被新增至目前文檔種類或合併至已存在同名的選項卡中。 - 此內容種類已經用於集合中,因此不能重複添加本身。 - 沒有可用於集合的內容種類。 - 可用的編輯器 - 重複使用 - 編輯器設定 - 設定 - 是,刪除 - 已移至下層 - 已複製至下層 - 選擇要移動的資料夾 - 選擇要複製的資料夾 - 至下方樹狀結構 - 所有文檔種類 - 所有文檔 - 所有媒體項目 - 使用此文檔種類的將被永久刪除,請確認您也想要將它們刪除。 - 使用此媒體種類的將被永久刪除,請確認您也想要將它們刪除。 - 使用此會員種類的將被永久刪除,請確認您也想要將它們刪除。 - 以及所有使用此種類的文件項目 - 以及所有使用此種類的媒體項目 - 以及所有使用此種類的會員項目 - 會員可以編輯 - 顯示於會員資料 - - - 替代欄位 - 替代文本 - 大小寫 - 編碼 - 選取欄位 - 轉換分行符號 - 將換行符號取代成為HTML標籤 &lt;br&gt; - 自訂欄位 - 是,僅日期 - 格式化時間 - HTML編碼 - 將替換HTML中的特殊字元 - 將在欄位值後插入 - 將在欄位值前插入 - 小寫 - - 欄位後插入 - 欄位前插入 - 遞迴 - 標準欄位 - 大寫 - URL編碼 - 將格式化URL中的特殊字元 - 當上面欄位值為空時使用 - 該欄位僅在主欄位為空時使用 - 是,含時間,分隔符號為: - - - 翻譯詳情 - 下載 XML DTD - 欄位 - 包含子頁 - - 沒有翻譯員,請創建翻譯員角色的用戶。 - 頁面'%0%'已經發送給翻譯 - 發送頁面'%0%'以便翻譯 - 總字數 - 翻譯到 - 翻譯完成。 - 您可以流覽剛翻譯的頁面,如果原始頁存在,您將得到兩者的比較。 - 翻譯失敗,XML可能損壞了。 - 翻譯選項 - 翻譯員 - 上傳翻譯的xml - - - 緩存流覽 - 回收站 - 創建擴展包 - 資料類型 - 字典 - 已安裝的擴展包 - 安裝皮膚 - 安裝新手套件 - 語言 - 安裝本地擴展包 - 巨集 - 媒體類型 - 會員 - 會員組 - 角色 - 會員類型 - 文檔類型 - 相關類型 - 擴展包 - 擴展包 - 從線上程式庫安裝 - 安裝Runway - Runway模組 - Scripting文件 - 腳本 - 樣式表 - 範本 - - - 有可用更新 - %0%已就緒,點擊這裡下載 - 無到伺服器的連接 - 檢查更新失敗 - - - 管理員 - 分類欄位 - 更改密碼 - 更改密碼 - 確認新密碼 - 要改變密碼,請在框中輸入新密碼,然後按一下“更改密碼”。 - 內容頻道 - 描述欄位 - 禁用用戶 - 文檔類型 - 編輯 - 排除欄位 - 語言 - 登錄 - 默認打開媒體項 - 區域 - 禁用後臺管理介面 - 舊的密碼 - 密碼 - 重設密碼 - 您的密碼已更改! - 重輸密碼 - 輸入新密碼 - 新密碼不能為空! - 當前密碼 - 密碼錯誤 - 新密碼和重輸入的密碼不一致,請重試! - 重輸的密碼和原密碼不一致! - 替換子項許可權設置 - 您正在修改存取權限的頁面: - 選擇要修改許可權的頁 - 搜索子物件 - 預設打開內容項 - 用戶名 - 用戶許可權 - 撰稿人 - 改變 - 您的個人檔案 - 您的歷程記錄 - 連線到期於 - - - 驗證 - 以電子郵件驗證 - 以數字驗證 - 以網址驗證 - ...或輸入自訂驗證 - 必要欄位 - - - - 數值已設為推薦值:%0% - 在設定檔 %3% 中XPath %2% 的數值設為 %1% 。 - 在設定檔 %3% 中XPath %2% 的預期值設為 %1% ,但卻是 %0%。 - 在設定檔 %3% 中XPath %2% 的值為非預期值 %0%。 - - 自訂錯誤設定為 %0% - 自訂錯誤設定為 %0。建議在上線前改為 %1%。 - 自訂錯誤成功設定為 %0% - 巨集錯誤設為 %0% - 巨集錯誤設為 %0%,如此一來,當巨集有任何錯誤時會阻止某些或全部頁面正常載入。改正會將此設定 %1%。 - 巨集錯誤已設為 %0% - - 嘗試略過IIS自訂錯誤目前設為 %0%,而且您使用的IIS版本為 %1%。 - 嘗試略過IIS自訂錯誤目前設為 %0%,然而在您使用的IIS版本為 %2% 時,建議設定是 %1%。 - 嘗試略過IIS自訂錯誤已成功設為 %0%。 - - 檔案不存在:%0%。 - '%1%'中無法找到'%0%'。]]> - 有錯誤產生,請參閱下列錯誤的紀錄:%0%。 - 憑證驗證錯誤:%0% - 網址探查錯誤:%0% - '%1%' - 您目前使用HTTPS瀏覽本站:%0% - 在您的web.config檔案中,appSetting的umbracoUseSSL是設為false。當您開始使用HTTPS時,應將其改為 true。 - 在您的web.config檔案中,appSetting的umbracoUseSSL是設為 %0%,您的cookies %0% 標成安全。 - 無法在您的web.config檔案中,更新appSetting的umbracoUseSSL設定,錯誤訊息:%0% - - 開啟HTTPS - 在web.config檔案中,將appSetting的umbracoUseSSL設true。 - 在您的web.config檔案中,appSetting的umbracoUseSSL已設為 true,您的cookies 將被標成安全。 - 修正 - 無法修正比較種類檢查為'ShouldNotEqual'。 - 用提供的數值無法修正比較種類檢查為'ShouldEqual'。 - 沒有提供要修正檢查的數值。 - 偵錯編輯模式關閉。 - 偵錯編輯模式目前已開啟。上線前建議將其關閉。 - 偵錯編輯模式已成功關閉。 - 詳細記錄模式已關閉。 - 詳細記錄模式目前已開啟。上線前建議將其關閉。 - 詳細記錄模式已成功關閉。 - 所有資料夾已有正確權限設定。 - - %0%。]]> - %0%。如果無須寫入,不需採取行動。]]> - 所有檔案已有正確權限設定。 - - %0%。]]> - %0%。如果無須寫入,不需採取行動。]]> - X-Frame-Options 設定能控制網站是否可以被其他人IFRAMEd已找到。]]> - X-Frame-Options 設定能控制網站是否可以被其他人IFRAMEd沒有找到。]]> - 調整設定的標頭 - 在 web.config 的 httpProtocol/customHeaders 區域增加設定來防止本站被別的網站IFRAMEd。 - 在 web.config 的 httpProtocol/customHeaders 區域已經增加設定來防止本站被別的網站IFRAMEd。 - 無法更新web.config檔案,錯誤:%0% - - %0%。]]> - 在標頭中沒有找到揭露網站技術的資訊。 - 在 Web.config 檔案中,找不到 system.net/mailsettings。 - 在 Web.config 檔案中的 system.net/mailsettings,沒有設定 host 。 - SMTP設定正確,而且服務正常運作。 - SMTP伺服器 %0% : %1% 無法連接。請確認在Web.config 檔案中 system.net/mailsettings 設定正確。 - %0%。]]> - %0%。]]> - - - 停止網址追蹤器 - 啟動網址追蹤器 - 原本網址 - 轉址成 - 沒有任何轉址 - 當發佈後的頁面改名或移動時,會自動轉址至新網頁。 - 移除 - 您確定要移除從 %0% 到 %1% 的轉址嗎? - 轉址已移除。 - 移除轉址錯誤。 - - 您確定要停止轉址追蹤器? - 轉址追蹤器已停止。 - 停止轉址追蹤器錯誤,更多資訊請參閱您的紀錄檔。 - 轉址追蹤器已開啟。 - 啟動轉址追蹤器錯誤,更多資訊請參閱您的紀錄檔。 - -
From d0016d6a7e86b42969757ba38839d538f9c3fc1f Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 10:40:04 +0100 Subject: [PATCH 127/223] Upgrade to MB -alpha.33 supporting elements --- build/NuSpecs/UmbracoCms.nuspec | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index 1b7a1c5ae1..3cb3d0d875 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -22,7 +22,7 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index ca4acd9d66..6967ac74c2 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -107,7 +107,7 @@ - 8.0.0-alpha.32 + 8.0.0-alpha.33 From c4418185ec2e83d48c335d1ca6860b27f427dba5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 21:27:14 +1100 Subject: [PATCH 128/223] Gets the angular view loading and allows navigating back to the view, cleans up non used lang keys --- .../Packaging/CompiledPackageXmlParser.cs | 2 +- .../Packaging/PackageDefinitionXmlParser.cs | 8 +- .../Packaging/PackagesRepository.cs | 86 +++++++++---------- .../mocks/services/localization.mocks.js | 7 -- .../src/common/resources/package.resource.js | 12 ++- src/Umbraco.Web.UI.Client/src/routes.js | 3 +- .../src/views/packages/edit.html | 10 +-- .../src/views/packages/options.controller.js | 43 ++++++++++ .../src/views/packages/options.html | 40 +++++++++ .../src/views/packages/overview.controller.js | 3 +- .../packages/views/installed.controller.js | 5 ++ .../src/views/packages/views/installed.html | 19 ++-- src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/de.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 7 -- .../Umbraco/config/lang/en_us.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/es.xml | 8 -- src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/he.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/it.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/ja.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/ko.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/pl.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/pt.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/ru.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/tr.xml | 7 -- src/Umbraco.Web.UI/Umbraco/config/lang/zh.xml | 7 -- .../Umbraco/config/lang/zh_tw.xml | 7 -- src/Umbraco.Web.UI/umbraco/config/lang/nb.xml | 7 -- .../umbraco/config/lang/zh_tw.xml | 7 -- src/Umbraco.Web/Editors/PackageController.cs | 22 ++--- .../Editors/PackageInstallController.cs | 11 +-- .../ContentEditing/InstalledPackageModel.cs | 39 --------- src/Umbraco.Web/Umbraco.Web.csproj | 1 - 38 files changed, 180 insertions(+), 286 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packages/options.html delete mode 100644 src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 7f62f4fd27..9e6339178e 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -51,7 +51,7 @@ namespace Umbraco.Core.Packaging IconUrl = package.Element("iconUrl")?.Value, UmbracoVersion = new Version((int)requirements.Element("major"), (int)requirements.Element("minor"), (int)requirements.Element("patch")), UmbracoVersionRequirementsType = requirements.AttributeValue("type").IsNullOrWhiteSpace() ? RequirementsType.Legacy : Enum.Parse(requirements.AttributeValue("type"), true), - PackageView = package.Element("view")?.Value, + PackageView = xml.Root.Element("view")?.Value, Actions = xml.Root.Element("Actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value Files = xml.Root.Element("files")?.Elements("file")?.Select(CompiledPackageFile.Create).ToList() ?? new List(), Macros = xml.Root.Element("Macros")?.Elements("macro") ?? Enumerable.Empty(), diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 00255fa43a..b66cdb095c 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -34,6 +34,7 @@ namespace Umbraco.Core.Packaging PackageId = xml.AttributeValue("packageGuid"), IconUrl = xml.AttributeValue("iconUrl") ?? string.Empty, UmbracoVersion = xml.AttributeValue("umbVersion"), + PackageView = xml.AttributeValue("view") ?? string.Empty, License = xml.Element("license")?.Value ?? string.Empty, LicenseUrl = xml.Element("license")?.AttributeValue("url") ?? string.Empty, Author = xml.Element("author")?.Value ?? string.Empty, @@ -49,8 +50,7 @@ namespace Umbraco.Core.Packaging Languages = xml.Element("languages")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), DataTypes = xml.Element("datatypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), - Files = xml.Element("files")?.Elements("file").Select(x => x.Value).ToList() ?? new List(), - PackageView = xml.Element("view")?.Value ?? string.Empty + Files = xml.Element("files")?.Elements("file").Select(x => x.Value).ToList() ?? new List() }; return retVal; @@ -77,6 +77,7 @@ namespace Umbraco.Core.Packaging new XAttribute("iconUrl", def.IconUrl ?? string.Empty), new XAttribute("umbVersion", def.UmbracoVersion), new XAttribute("packageGuid", def.PackageId), + new XAttribute("view", def.PackageView ?? string.Empty), new XElement("license", new XCData(def.License ?? string.Empty), @@ -100,8 +101,7 @@ namespace Umbraco.Core.Packaging new XElement("macros", string.Join(",", def.Macros ?? Array.Empty())), new XElement("files", (def.Files ?? Array.Empty()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))), new XElement("languages", string.Join(",", def.Languages ?? Array.Empty())), - new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty())), - new XElement("view", def.PackageView ?? string.Empty)); + new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty()))); return packageXml; } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index 5531e05705..1df232f62d 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -161,30 +161,30 @@ namespace Umbraco.Core.Packaging try { //Init package file - var packageManifest = CreatePackageManifest(out var manifestRoot, out var filesXml); + var compiledPackageXml = CreateCompiledPackageXml(out var root, out var filesXml); //Info section - manifestRoot.Add(GetPackageInfoXml(definition)); + root.Add(GetPackageInfoXml(definition)); - PackageDocumentsAndTags(definition, manifestRoot); - PackageDocumentTypes(definition, manifestRoot); - PackageTemplates(definition, manifestRoot); - PackageStylesheets(definition, manifestRoot); - PackageMacros(definition, manifestRoot, filesXml, temporaryPath); - PackageDictionaryItems(definition, manifestRoot); - PackageLanguages(definition, manifestRoot); - PackageDataTypes(definition, manifestRoot); + PackageDocumentsAndTags(definition, root); + PackageDocumentTypes(definition, root); + PackageTemplates(definition, root); + PackageStylesheets(definition, root); + PackageMacros(definition, root, filesXml, temporaryPath); + PackageDictionaryItems(definition, root); + PackageLanguages(definition, root); + PackageDataTypes(definition, root); //Files foreach (var fileName in definition.Files) - AppendFileToManifest(fileName, temporaryPath, filesXml); + AppendFileToPackage(fileName, temporaryPath, filesXml); - //Load control on install... + //Load view on install... if (!string.IsNullOrEmpty(definition.PackageView)) { var control = new XElement("view", definition.PackageView); - AppendFileToManifest(definition.PackageView, temporaryPath, filesXml); - manifestRoot.Add(control); + AppendFileToPackage(definition.PackageView, temporaryPath, filesXml); + root.Add(control); } //Actions @@ -196,20 +196,20 @@ namespace Umbraco.Core.Packaging //this will be formatted like a full xml block like ... and we want the child nodes var parsed = XElement.Parse(definition.Actions); actionsXml.Add(parsed.Elements()); - manifestRoot.Add(actionsXml); + root.Add(actionsXml); } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package manifest, the xml did not parse"); + _logger.Warn(e, "Could not add package actions to the package, the xml did not parse"); } } - var manifestFileName = temporaryPath + "/package.xml"; + var packageXmlFileName = temporaryPath + "/package.xml"; - if (File.Exists(manifestFileName)) - File.Delete(manifestFileName); + if (File.Exists(packageXmlFileName)) + File.Delete(packageXmlFileName); - packageManifest.Save(manifestFileName); + compiledPackageXml.Save(packageXmlFileName); // check if there's a packages directory below media @@ -242,7 +242,7 @@ namespace Umbraco.Core.Packaging throw new InvalidOperationException("Validation failed, there is invalid data on the model: " + string.Join(", ", results.Select(x => x.ErrorMessage))); } - private void PackageDataTypes(PackageDefinition definition, XContainer manifestRoot) + private void PackageDataTypes(PackageDefinition definition, XContainer root) { var dataTypes = new XElement("DataTypes"); foreach (var dtId in definition.DataTypes) @@ -252,10 +252,10 @@ namespace Umbraco.Core.Packaging if (dataType == null) continue; dataTypes.Add(_serializer.Serialize(dataType)); } - manifestRoot.Add(dataTypes); + root.Add(dataTypes); } - private void PackageLanguages(PackageDefinition definition, XContainer manifestRoot) + private void PackageLanguages(PackageDefinition definition, XContainer root) { var languages = new XElement("Languages"); foreach (var langId in definition.Languages) @@ -265,10 +265,10 @@ namespace Umbraco.Core.Packaging if (lang == null) continue; languages.Add(_serializer.Serialize(lang)); } - manifestRoot.Add(languages); + root.Add(languages); } - private void PackageDictionaryItems(PackageDefinition definition, XContainer manifestRoot) + private void PackageDictionaryItems(PackageDefinition definition, XContainer root) { var dictionaryItems = new XElement("DictionaryItems"); foreach (var dictionaryId in definition.DictionaryItems) @@ -278,10 +278,10 @@ namespace Umbraco.Core.Packaging if (di == null) continue; dictionaryItems.Add(_serializer.Serialize(di, false)); } - manifestRoot.Add(dictionaryItems); + root.Add(dictionaryItems); } - private void PackageMacros(PackageDefinition definition, XContainer manifestRoot, XContainer filesXml, string temporaryPath) + private void PackageMacros(PackageDefinition definition, XContainer root, XContainer filesXml, string temporaryPath) { var macros = new XElement("Macros"); foreach (var macroId in definition.Macros) @@ -291,14 +291,14 @@ namespace Umbraco.Core.Packaging var macroXml = GetMacroXml(outInt, out var macro); if (macroXml == null) continue; macros.Add(macroXml); - //if the macro has a file copy it to the manifest + //if the macro has a file copy it to the xml if (!string.IsNullOrEmpty(macro.MacroSource)) - AppendFileToManifest(macro.MacroSource, temporaryPath, filesXml); + AppendFileToPackage(macro.MacroSource, temporaryPath, filesXml); } - manifestRoot.Add(macros); + root.Add(macros); } - private void PackageStylesheets(PackageDefinition definition, XContainer manifestRoot) + private void PackageStylesheets(PackageDefinition definition, XContainer root) { var stylesheetsXml = new XElement("Stylesheets"); foreach (var stylesheetName in definition.Stylesheets) @@ -308,10 +308,10 @@ namespace Umbraco.Core.Packaging if (xml != null) stylesheetsXml.Add(xml); } - manifestRoot.Add(stylesheetsXml); + root.Add(stylesheetsXml); } - private void PackageTemplates(PackageDefinition definition, XContainer manifestRoot) + private void PackageTemplates(PackageDefinition definition, XContainer root) { var templatesXml = new XElement("Templates"); foreach (var templateId in definition.Templates) @@ -321,10 +321,10 @@ namespace Umbraco.Core.Packaging if (template == null) continue; templatesXml.Add(_serializer.Serialize(template)); } - manifestRoot.Add(templatesXml); + root.Add(templatesXml); } - private void PackageDocumentTypes(PackageDefinition definition, XContainer manifestRoot) + private void PackageDocumentTypes(PackageDefinition definition, XContainer root) { var contentTypes = new HashSet(); var docTypesXml = new XElement("DocumentTypes"); @@ -338,10 +338,10 @@ namespace Umbraco.Core.Packaging foreach (var contentType in contentTypes) docTypesXml.Add(_serializer.Serialize(contentType)); - manifestRoot.Add(docTypesXml); + root.Add(docTypesXml); } - private void PackageDocumentsAndTags(PackageDefinition definition, XContainer manifestRoot) + private void PackageDocumentsAndTags(PackageDefinition definition, XContainer root) { //Documents and tags if (string.IsNullOrEmpty(definition.ContentNodeId) == false && int.TryParse(definition.ContentNodeId, out var contentNodeId)) @@ -356,7 +356,7 @@ namespace Umbraco.Core.Packaging //Create the Documents/DocumentSet node - manifestRoot.Add( + root.Add( new XElement("Documents", new XElement("DocumentSet", new XAttribute("importMode", "root"), @@ -438,12 +438,12 @@ namespace Umbraco.Core.Packaging } /// - /// Appends a file to package manifest and copies the file to the correct folder. + /// Appends a file to package and copies the file to the correct folder. /// /// The path. /// The package directory. /// The files xml node - private static void AppendFileToManifest(string path, string packageDirectory, XContainer filesXml) + private static void AppendFileToPackage(string path, string packageDirectory, XContainer filesXml) { if (!path.StartsWith("~/") && !path.StartsWith("/")) path = "~/" + path; @@ -584,12 +584,12 @@ namespace Umbraco.Core.Packaging return info; } - private static XDocument CreatePackageManifest(out XElement root, out XElement files) + private static XDocument CreateCompiledPackageXml(out XElement root, out XElement files) { files = new XElement("files"); root = new XElement("umbPackage", files); - var packageManifest = new XDocument(root); - return packageManifest; + var compiledPackageXml = new XDocument(root); + return compiledPackageXml; } private XDocument EnsureStorage(out string packagesFile) diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js index ec1175ab6c..87955739fb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js @@ -453,13 +453,11 @@ angular.module('umbraco.mocks'). "notifications_notifications": "Notifications", "packager_chooseLocalPackageText": " Choose Package from your machine, by clicking the Browse
button and locating the package. Umbraco packages usually have a '.umb' or '.zip' extension. ", "packager_packageAuthor": "Author", - "packager_packageDemonstration": "Demonstration", "packager_packageDocumentation": "Documentation", "packager_packageMetaData": "Package meta data", "packager_packageName": "Package name", "packager_packageNoItemsHeader": "Package doesn't contain any items", "packager_packageNoItemsText": "This package file doesn't contain any items to uninstall.

You can safely remove this from the system by clicking 'uninstall package' below.", - "packager_packageNoUpgrades": "No upgrades available", "packager_packageOptions": "Package options", "packager_packageReadme": "Package readme", "packager_packageRepository": "Package repository", @@ -468,12 +466,7 @@ angular.module('umbraco.mocks'). "packager_packageUninstalledText": "The package was successfully uninstalled", "packager_packageUninstallHeader": "Uninstall package", "packager_packageUninstallText": "You can unselect items you do not wish to remove, at this time, below. When you click 'confirm uninstall' all checked-off items will be removed.
Notice: any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, so uninstall with caution. If in doubt, contact the package author.", - "packager_packageUpgradeDownload": "Download update from the repository", - "packager_packageUpgradeHeader": "Upgrade package", - "packager_packageUpgradeInstructions": "Upgrade instructions", - "packager_packageUpgradeText": " There's an upgrade available for this package. You can download it directly from the Umbraco package repository.", "packager_packageVersion": "Package version", - "packager_viewPackageWebsite": "View package website", "paste_doNothing": "Paste with full formatting (Not recommended)", "paste_errorMessage": "The text you're trying to paste contains special characters or formatting. This could be caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so the pasted content will be more suitable for the web.", "paste_removeAll": "Paste as raw text without any formatting at all", diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 0d74d0fdd3..7519341327 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -175,7 +175,17 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { umbRequestHelper.getApiUrl( "packageApiBaseUrl", "GetCreatedPackageById", - [{ id: id }])), + { id: id })), + 'Failed to get package'); + }, + + getInstalledById: function (id) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "packageApiBaseUrl", + "GetInstalledPackageById", + { id: id })), 'Failed to get package'); }, diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js index 64bddb16e2..c2d3ea2df8 100644 --- a/src/Umbraco.Web.UI.Client/src/routes.js +++ b/src/Umbraco.Web.UI.Client/src/routes.js @@ -158,7 +158,8 @@ app.config(function ($routeProvider) { } //special case for the package section - if ($routeParams.section.toLowerCase() === "packages" && $routeParams.tree.toLowerCase() === "packages" && $routeParams.method !== "edit") { + var packagePages = ["edit", "options"]; + if ($routeParams.section.toLowerCase() === "packages" && $routeParams.tree.toLowerCase() === "packages" && packagePages.indexOf($routeParams.method.toLowerCase()) === -1) { $scope.templateUrl = "views/packages/overview.html"; return; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 5163fadfb5..5ad5ac2522 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -255,13 +255,13 @@ + label="Package options view" + description="Load this view after installation (ex: App_Plugins/MyApp/MyPackageOptions.html). It can be used to configure your package at any time by clicking Options on the installed package listing"> diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js new file mode 100644 index 0000000000..8ffd282e0d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js @@ -0,0 +1,43 @@ +(function () { + "use strict"; + + function OptionsController($scope, $location, $routeParams, packageResource, umbRequestHelper) { + + const vm = this; + + vm.showBackButton = true; + vm.loading = true; + vm.back = back; + + const packageId = $routeParams.id; + + function onInit() { + + packageResource.getInstalledById(packageId).then(pck => { + vm.package = pck; + vm.loading = false; + + //make sure the packageView is formatted as a virtual path + pck.packageView = pck.packageView.startsWith("/~") + ? pck.packageView + : pck.packageView.startsWith("/") + ? "~" + pck.packageView + : "~/" + pck.packageView; + + pck.packageView = umbRequestHelper.convertVirtualToAbsolutePath(pck.packageView); + + }); + } + + function back() { + $location.path("packages/packages/installed"); + } + + + onInit(); + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.OptionsController", OptionsController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/options.html b/src/Umbraco.Web.UI.Client/src/views/packages/options.html new file mode 100644 index 0000000000..d75604d094 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packages/options.html @@ -0,0 +1,40 @@ +
+ +
+ + + + + + + + + + +

+ This package has no configuration view +

+ +
+ +
+ + + + +
+ +
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index 59fa79dc26..f4c1ab9de4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -17,8 +17,7 @@ } if (installPackageUri && installPackageUri !== "installed") { - //navigate to the custom installer screen, if it is just "installed", then we'll - //show the installed view + //navigate to the custom installer screen, if it is just "installed" it means there is no custom installer screen $location.path(installPackageUri).search(""); } else { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js index 5265897708..3b6422ace4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js @@ -7,6 +7,7 @@ vm.confirmUninstall = confirmUninstall; vm.uninstallPackage = uninstallPackage; + vm.packageOptions = packageOptions; vm.state = "list"; vm.installState = { status: "" @@ -34,6 +35,10 @@ }); } + function packageOptions(pck) { + $location.path("packages/packages/options/" + pck.id); + } + function confirmUninstall(pck) { vm.state = "packageDetails"; vm.package = pck; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html index 3c443e0bac..888bf02c4e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html @@ -23,12 +23,19 @@
- + + + + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml index f3b16def54..db780bb358 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml @@ -617,14 +617,12 @@ a výběrem balíčku. Balíčky umbraco mají obvykle přípony ".umb" nebo ".zip". ]]> Autor - Ukázka Dokumentace Meta data balíčku Název balíčku Balíček neobsahuje žádné položky
Můžete jej ze systému bezpečně odstranit kliknutím na "odebrat balíček" níže.]]>
- Žádné aktualizace nejsou dostupné Možnosti balíčku Čti mě balíčku Úložiště balíčku @@ -635,12 +633,7 @@ Upozornění: všechny dokumenty, media atd. závislé na položkách, které odstraníte, přestanou pracovat a mohou vést k nestabilitě systému, takže odinstalovávejte opatrně. Jste-li na pochybách, kontaktujte autora balíčku.]]> - Stáhnout aktualizaci z úložiště - Balíček s aktualizací - Pokyny pro aktualizaci - Pro tento balíček je dostupná aktualizace. Můžete si ji stáhnout přímo z úložiště balíčků umbraco. Verze balíčku - Zobrazit web balíčku Vložit s úplným formatováním (nedoporučeno) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index 523531947a..39e1341f37 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -840,13 +840,11 @@ Mange hilsner fra Umbraco robotten Denne pakke er kompatibel med de følgende versioner af Umbraco, som rapporteret af community-medlemmer. Fuld kompatibilitet kan ikke garanteres for versioner rapporteret nedenfor 100% Eksterne kilder Forfatter - Demonstration Dokumentation Pakke meta data Pakkenavn Pakken indeholder ingen elementer
Du kan roligt fjerne denne fra systemet ved at klikke på "Fjern pakke" nedenfor.]]>
- Ingen opdateringer tilgængelige Pakkevalg Pakke læs mig Pakke opbevaringsbase @@ -856,12 +854,7 @@ Mange hilsner fra Umbraco robotten Afinstallér pakke Bemærk: at dokumenter og medier som afhænger af denne pakke vil muligvis holde op med at virke, så vær forsigtig. Hvis i tvivl, kontakt personen som har udviklet pakken.]]> - Download opdatering fra opbevaringsbasen - Opdatér pakke - Opdateringsinstrukser - Der er en tilgængelig opdatering til denne pakke. Du kan downloade den direkte fra Umbracos pakke opbevaringsbase. Pakke version - Se pakkeudviklerens website Pakke allerede installeret Denne pakke kan ikke installeres, den kræver en minimum Umbraco version af Afinstallerer... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml index 915b25208e..1be81fb10f 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml @@ -610,13 +610,11 @@ Wenn Sie sich für Runway entscheiden, können Sie optional Blöcke nutzen, die Wählen Sie ein Paket auf Ihrem lokalen Computer über "Datei auswählen" aus. <br />Umbraco-Pakete besitzen üblicherweise die Dateiendungen ".umb" oder ".zip". Autor - Demonstration Dokumentation Paket-Meta-Daten Name des Pakets Paket enthält keine Elemente Die Paket-Datei enthält keine Elemente die deinstalliert werden können.<br/><br/>Sie können das Paket ohne Gefahr deinstallieren indem Sie "Paket deinstallieren" anklicken. - Keine Updates für das Paket verfügbar Paket-Optionen Informationen zum Paket Paket-Repository @@ -625,12 +623,7 @@ Wenn Sie sich für Runway entscheiden, können Sie optional Blöcke nutzen, die Das Paket wurde erfolgreich deinstalliert Paket deinstallieren Sie können einzelne Elemente, die Sie nicht deinstallieren möchten, unten abwählen. Wenn Sie "Deinstallation bestätigen" klicken, werden alle markierten Elemente entfernt.<br /><span style="color: Red; font-weight: bold;">Achtung:</span> alle Dokumente, Medien, etc, die von den zu entfernenden Elementen abhängen, werden nicht mehr funktionieren und im Zweifelsfall kann dass gesamte CMS instabil werden. Bitte deinstallieren Sie also mit Vorsicht. Falls Sie unsicher sind, kontaktieren Sie den Autor des Pakets. - Update vom Paket-Repository herunterladen - Paket-Update - Hinweise für die Durchführung des Updates - Es ist ein Update für dieses Paket verfügbar. Sie können es direkt vom Umbraco-Paket-Repository herunterladen. Version des Pakets - Paket-Webseite aufrufen Einfügen mit Formatierung (Nicht empfohlen) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index dad27d99fe..d50cac4ac4 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1090,14 +1090,12 @@ To manage your website, simply open the Umbraco back office and start adding con This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be gauranteed for versions reported below 100% External sources Author - Demonstration Documentation Package meta data Package name Package doesn't contain any items
You can safely remove this from the system by clicking "uninstall package" below.]]>
- No upgrades available Package options Package readme Package repository @@ -1108,12 +1106,7 @@ To manage your website, simply open the Umbraco back office and start adding con Notice: any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, so uninstall with caution. If in doubt, contact the package author.]]> - Download update from the repository - Upgrade package - Upgrade instructions - There's an upgrade available for this package. You can download it directly from the Umbraco package repository. Package version - View package website Package already installed This package cannot be installed, it requires a minimum Umbraco version of Uninstalling... 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 ab37cf8025..23efe8047e 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1117,14 +1117,12 @@ To manage your website, simply open the Umbraco back office and start adding con This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be gauranteed for versions reported below 100% External sources Author - Demonstration Documentation Package meta data Package name Package doesn't contain any items
You can safely remove this from the system by clicking "uninstall package" below.]]>
- No upgrades available Package options Package readme Package repository @@ -1135,13 +1133,8 @@ To manage your website, simply open the Umbraco back office and start adding con Notice: any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, so uninstall with caution. If in doubt, contact the package author.]]> - Download update from the repository - Upgrade package - Upgrade instructions - There's an upgrade available for this package. You can download it directly from the Umbraco package repository. Package version Upgrading from version - View package website Package already installed This package cannot be installed, it requires a minimum Umbraco version of Uninstalling... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/es.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/es.xml index 7f35e90083..090ecc875e 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/es.xml @@ -863,14 +863,11 @@ Este paquete es compatible con las siguientes versiones de Umbraco, declaradas según miembros de la comunidad. No se puede garantizar compatibilidad completa para versiones declaradas debajo del 100% Fuentes externas Autor - Documentación Meta datos del paquete Nombre del paquete El paquete no contiene ningún elemento
Puedes eliminarlo del sistema de forma segura seleccionando la opción "desinstalar paquete" de abajo.]]>
- No hay actualizaciones disponibles Opciones del paquete Léeme del paquete Repositorio de paquetes @@ -879,12 +876,7 @@ El paquete se ha desinstalado correctamente Desinstalar paquete Nota: cualquier documento, archivo etc dependiente de los elementos eliminados, dejará de funcionar, y puede conllevar inestabilidad en el sistema, por lo que lleva cuidado al desinstalar elementos. En caso de duda, contacta con el autor del paquete.]]> - Descargar actualización del repositorio - Actualizar paquete - Instrucciones de actualización - Hay una actualización disponible para este paquete. Puedes descargarla directamente del repositorio de paquetes de Umbraco. Versión del paquete - Ver página web del paquete Paquete ya instalado Este paquete no se puede instalar, requiere un versión mínima de Umbraco de Desinstalando... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml index 04b2cea4df..b6c23d7b63 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml @@ -1025,14 +1025,12 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Ce package est compatible avec les versions suivantes de Umbraco, selon les rapports des membres de la communauté. Une compatibilité complète ne peut pas être garantie pour les versions rapportées sous 100% Sources externes Auteur - Démo Documentation Meta data du package Nom du package Le package ne contient aucun élément
Vous pouvez supprimer tranquillement ce package de votre installation en cliquant sur "Désinstaller le package" ci-dessous.]]>
- Aucune mise à jour disponible Options du package Package readme Repository des packages @@ -1043,12 +1041,7 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Remarque : tous les documents, media etc. dépendant des éléments que vous supprimez vont cesser de fonctionner, ce qui peut provoquer une instabilité du système, désinstallez donc avec prudence. En cas de doute, contactez l'auteur du package.]]> - Télécharger la mise à jour depuis le repository - Mettre à jour le package - Instructions de mise à jour - Il y a une mise à jour disponible pour ce package. Vous pouvez la télécharger directement depuis le repository des packages Umbraco. Version du package - Voir le site internet du package Package déjà installé Ce package ne peut pas être installé, il nécessite au minimum la version Umbraco %0% Désinstallation... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/he.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/he.xml index 011745ac0f..8d3822943a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/he.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/he.xml @@ -548,14 +548,12 @@ To manage your website, simply open the Umbraco back office and start adding con ויש לבחור את החבילה הרצויה. לחבילות Umbraco יש בד"כ יש סיומות בשם ".umb" או ".zip". ]]> יוצר החבילה - הדגמה תיעוד מטה דטה עבור החבילה שם החבילה החבילה לא מכילה אף פריט
ניתן למחוק בבטיחות רבה את החבילה מהמערכת על ידי לחיצה על "הסר חבילה".]]>
- אין עידכונים זמינים אפשרויות חבילה תיאור החבילה מאגר חבילות @@ -566,12 +564,7 @@ To manage your website, simply open the Umbraco back office and start adding con הערה:כל מסמך, מדיה וכו' התלוים בפריטים שהסרת יפסיקו לעבוד, ויכולים להביא למצב של אי יציבות למערכת, יש למחוק קבצים עם זהירות יתרה, אם יש ספק יש לפנות ליוצר החבילה.]]> - הורד עידכון מהמאגר - שידרוג חבילה - הורדות שידרוג - קיים עידכון זמין עבור חבילה זו. ניתן להוריד אותו ישירות ממאגר החבילות של אומברקו. גירסת החבילה - צפה באתר החבילה שמור עיצוב בהדבקה (לא מומלץ) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/it.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/it.xml index a55c626625..6796fdfc3c 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/it.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/it.xml @@ -524,14 +524,12 @@ Per gestire il tuo sito web, è sufficiente aprire il back office di Umbraco e i e selezionando il pacchetto. I pacchetti Umbraco generalmente hanno l'estensione ".umb" o ".zip". ]]> Autore - Dimostrazione Documentazione Meta dati pacchetto Nome del pacchetto Il pacchetto non contiene tutti gli elementi
E' possibile rimuovere questo pacchetto dal sistema cliccando "rimuovi pacchetto" in basso.]]>
- Non ci sono aggiornamenti disponibili Opzioni pacchetto Pacchetto leggimi Pacchetto repository @@ -542,12 +540,7 @@ Per gestire il tuo sito web, è sufficiente aprire il back office di Umbraco e i Avviso: tutti i documenti, i media, etc a seconda degli elementi che rimuoverai, smetteranno di funzionare, e potrebbero portare a un'instabilità del sistema, perciò disinstalla con cautela. In caso di dubbio contattare l'autore del pacchetto.]]> - - Aggiorna pacchetto - - Versione del pacchetto - Vedi sito web pacchetto diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/ja.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/ja.xml index 993a99ceec..ae30fde3c4 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/ja.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/ja.xml @@ -692,14 +692,12 @@ Runwayをインストールして作られた新しいウェブサイトがど パッケージを選択できます。Umbracoのパッケージは概ね".zip"ないしは".umb"といった拡張子です。 ]]> 作成者 - デモ ヘルプ パッケージのメタデータ パッケージ名 パッケージには何も含まれません
"パッケージのアンインストール"をクリックしてシステムから安全に削除できます。]]>
- 更新はありません パッケージのオプション パッケージの取扱説明書 パッケージリポジトリ @@ -710,12 +708,7 @@ Runwayをインストールして作られた新しいウェブサイトがど 注意: 全ての、文書やメディアなどに依存したアイテムを削除する場合はそれらの作業を一端止めてからアンインストールしなければシステムが不安定になる恐れがあります。 疑問点などあればパッケージの作者へ連絡してください。]]> - リポジトリからアップデートをダウンロード - パッケージのアップグレード - 更新の手順 - このパッケージの更新があります。Umbracoのパッケージリポジトリから直接ダウンロードできます。 パッケージのバージョン - パッケージのウェブサイトを見る 完全な書式を含んだまま貼り付け (非推奨) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/ko.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/ko.xml index 7a46ea81c8..7507ca07e8 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/ko.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/ko.xml @@ -532,14 +532,12 @@ Umbraco 패키지는 보통 ".umb" 나 ".zip" 확장자를 가집니다. ]]> 저자 - 데모 문서화 패키지 메타데이터 패키지 이름 패키지가 포함한 아이템이 없습니다.
아래 "패키지 삭제"를 클릭하시면 안전하게 시스템에서 삭제하실 수 있습니다.]]>
- 업그레이드할 패키지가 없습니다. 패키지 옵션 패키지 정보 패키지 저장소 @@ -550,12 +548,7 @@ 알림: 문서, 미디어등 삭제항목에 관련된 모든 항목이 삭제됩니다, 작업을 중단하면 시스템이 불안정적으로 동작할 수 있습니다. 삭제는 매우 주의를 요하기 때문에 의심스러운항목은 패키지 제작자에게 문의하시기 바랍니다.]]> - 저장소에서 업데이트 다운로드 - 업그레이드 패키지 - 업그레이드 지시사항 - 업그레이드할 패키지가 없습니다. Umbraco패키지 저장소에서 직접다운로드하실 수 있습니다. 패키지 버전 - 패키지 웹사이트 보기 포맷을 포함여하 붙여넣기(권장하지 않음) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index a3c8abb946..39f4dd9560 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -589,13 +589,11 @@ Vennlig hilsen Umbraco roboten Umbraco-pakker har vanligvis endelsen ".umb" eller ".zip".]]> Utvikler - Demonstrasjon Dokumentasjon Metadata Pakkenavn Pakken inneholder ingen elementer
Du kan trygt fjerne pakken fra systemet ved å klikke "avinstaller pakke" nedenfor.]]>
- Ingen oppdateringer tilgjengelig Alternativer for pakke Lesmeg for pakke Pakkebrønn @@ -604,12 +602,7 @@ Vennlig hilsen Umbraco roboten Pakken ble vellykket avinstallert Avinstaller pakke Advarsel: alle dokumenter, media, etc. som som er avhengig av elementene du sletter, vil slutte å virke, noe som kan føre til ustabilitet, så avinstaller med forsiktighet. Hvis du er i tvil, kontakt pakkeutvikleren.]]> - Last ned oppdatering fra pakkeregisteret - Oppgrader pakke - Oppgraderingsinstrukser - Det er en oppdatering tilgjengelig for denne pakken. Du kan laste den ned direkte fra pakkebrønnen. Pakkeversjon - Se pakkens nettsted Lim inn med full formattering (Anbefales ikke) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml index 8189be9429..4722abb557 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nl.xml @@ -698,7 +698,6 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Kies een package op je computer door op "Bladeren" te klikken en de package te selecteren. Umbraco packages hebben meestal ".umb" of ".zip" als extensie. Auteur - Demonstratie Documentatie Package meta data Package naam @@ -706,7 +705,6 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je
Je kunt deze package veilig verwijderen door op 'verwijder package' te klikken. ]]>
- Geen upgrades beschikbaar Package opties Package lees mij Package repository @@ -718,12 +716,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Waarschuwing: alle documenten, media etc, die afhankelijk zijn van de items die je verwijderd, zullen niet meer werken en kan leiden tot een instabiele installatie, wees dus voorzichtig met verwijderen. Als je het niet zeker weet, neem dan contact op met de auteur van de package. ]]> - Download update uit de repository - Upgrade package - Upgrade instructies - Er is een upgrade beschikbaar voor deze package. Je kunt het direct downloaden uit de Umbraco package repository. Package versie - Bekijk de package website Package reeds geinstalleerd Deze package kan niet worden geinstalleerd omdat minimaal Umbraco versie %0% benodigd is. Aan het deinstalleren... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/pl.xml index 1f64a5ab21..788afd3c1a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/pl.xml @@ -859,14 +859,12 @@ Naciśnij przycisk instaluj, aby zainstalować bazę danych Umb Według raportów członków społeczności, ten pakiet jest zgodny z następującymi wersjami Umbraco. Pełna zgodność nie może być zagwarantowana dla wersji zaraportowanych poniżej 100% Zewnętrzne źródła Autor - Demonstracja Dokumentacja Metadane pakietu Nazwa pakietu Pakiet nie zawiera żadnych elementów
Możesz bezpiecznie go usunąć z systemu poprzez kliknięcie na przycisku "odinstaluj pakiet"]]>
- Nie ma dostępnych aktualizacji Opcje pakietu Opis pakietu Repozytorium pakietu @@ -877,12 +875,7 @@ Naciśnij przycisk instaluj, aby zainstalować bazę danych Umb Uwaga: wszystkie elementy, media, itp. w zależności od elementów, które usuwasz, przestaną działać i mogą spowodować niestabilność systemu, więc odinstalowuj z uwagą. W przypadku problemów skontaktuj się z autorem pakietu.]]> - Pobierz aktualizację z repozytorium - Aktualizuj pakiet - Instrukcja aktualizacji - Jest dostępna aktualizacja dla tego pakietu. Możesz ją pobrać wprost z repozytorium pakietów Umbraco. Wersja pakietu - Odwiedź stronę pakietu Pakiet jest już zainstalowany Ten pakiet nie może być zainstalowany, ponieważ wymaga Umbraco w wersji przynajmniej %0% Odinstalowywanie... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/pt.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/pt.xml index cff6009bb4..56297d23df 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/pt.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/pt.xml @@ -522,14 +522,12 @@ Vá até http://%4%/#/content/content/edit/%5% para editar. e localizando o pacote. Pacotes Umbraco tem extensão ".umb" ou ".zip".]]> Autor - Demonstração Documentação Dado meta do pacote Nome do pacote Pacote não contém nenhum item
Você pode remover com segurança do seu sistema clicando em "desinstalar pacote" abaixo.]]>
- Nenhuma atualização disponível Oções do pacote Leia-me do pacote Repositório do pacote @@ -539,12 +537,7 @@ Você pode remover com segurança do seu sistema clicando em "desinstalar pacote Desinstalar pacote Aviso: quaisquer documentos, mídia, etc dependentes dos itens que forem removidos vão parar de funcionar e podem levar à instabilidade do sistema. Então desinstale com cuidado. Se tiver dúvidas, contate o autor do pacote]]> - Baixar atualização pelo repositório - Atualizar pacote - Instruções de atualização - Há uma atualizaçào disponível para este pacote. Você pode baixá-lo diretamente do repositório de pacotes do Umbraco. Versão do pacote - Ver website do pacote Colar com formatação completa (Não recomendado) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/ru.xml index 61c42d9d6d..1744d19581 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/ru.xml @@ -1182,14 +1182,12 @@ Этот пакет совместим со следующими версиями Umbraco, по сообщениям участников сообщества. Полная совместимость не гарантируется для версий со значением ниже 100% Внешние источники Автор - Демонстрация Документация (описание) Мета-данные пакета Название пакета Пакет ничего не содержит
Вы можете безопасно удалить данный пакет из системы, нажав на кнопку "Деинсталлировать пакет".]]>
- Нет доступных обновлений Опции пакета Краткий обзор пакета Репозиторий пакета @@ -1200,12 +1198,7 @@ Обратите внимание: все документы, медиа-файлы и другой контент, зависящий от этого пакета, перестанет нормально работать, что может привести к нестабильному поведению системы, поэтому удаляйте пакеты очень осторожно. При наличии сомнений, свяжитесь с автором пакета.]]> - Скачать обновление из репозитория - Обновление пакета - Руководство по обновлению - Для данного пакета доступно обновление. Вы можете загрузить это обновление непосредственно из центрального репозитория пакетов Umbraco. Версия пакета - Перейти на веб-сайт пакета Этот пакет уже установлен в системе Этот пакет не может быть установлен, он требует наличия Umbraco версии как минимум Удаление... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml index 05c6dc927d..625caa0432 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml @@ -544,13 +544,11 @@ och leta upp paketet. Umbracos installationspaket har oftast filändelsen ".umb" eller ".zip".]]> Utvecklare - Demonstration Dokumentation Paket metadata Paketnamn Paketet innehåller inga poster
Det är säkert att ta bort den ur systemet genom att klicka på "avinstallera paket" nedan.]]>
- Inga uppdateringar tillgängliga Paketalternativ Paket läsmig Paketvalv @@ -559,12 +557,7 @@ Paketet har avinstallerats utan problem Avinstallera paket OBS! dokument, media osv som använder de borttagna posterna kommer sluta fungera vilket kan leda till att systemet blir instabilt. Avinstallera därför med försiktighet. Om du är osäker, kontakta personen som skapat paketet.]]> - Hämta uppdatering från paketvalvet - Uppdatera paket - Uppdateringsinstruktioner - Det finns an uppdaterad version av paketet. Du kan hämta den direkt från Umbracos paketvalv. Paketversion - Besök paketets webbplats Klistra in med helt bibehållen formatering (rekommenderas ej) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/tr.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/tr.xml index 4ff9d22c86..053430d68d 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/tr.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/tr.xml @@ -609,14 +609,12 @@ To manage your website, simply open the Umbraco back office and start adding con button and locating the package. Umbraco packages usually have a ".umb" or ".zip" extension. ]]> Author - Demonstration Documentation Package meta data Package name Package doesn't contain any items
You can safely remove this from the system by clicking "uninstall package" below.]]>
- No upgrades available Package options Package readme Package repository @@ -627,12 +625,7 @@ To manage your website, simply open the Umbraco back office and start adding con Notice: any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, so uninstall with caution. If in doubt, contact the package author.]]> - Download update from the repository - Upgrade package - Upgrade instructions - There's an upgrade available for this package. You can download it directly from the Umbraco package repository. Package version - View package website Paste with full formatting (Not recommended) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/zh.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/zh.xml index 7286c3f914..227e40cf94 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/zh.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/zh.xml @@ -728,14 +728,12 @@ 选择 ".umb" 或者 ".zip" 文件 ]]> 作者 - 演示 文档 元数据 名称 扩展包不含任何项
点击下面的“卸载”,您可以安全的删除。]]>
- 无可用更新 选项 说明 程序库 @@ -746,12 +744,7 @@ 注意: 卸载包将导致所有依赖该包的东西失效,请确认。 ]]> - 从程序库下载更新 - 更新扩展包 - 更新说明 - 此软件包有一个可用的升级。您可以直接从 Umbraco 软件包存储库下载。 版本 - 访问扩展包网站 已安装软件包 此软件包无法安装, 它需要一个最小的 Umbraco 版本的%0% 卸载中... diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml index b61e1154b8..23da0c817c 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml @@ -714,14 +714,12 @@ 按鈕並點選該檔案。Umbraco擴展包通常有「.zip」的副檔名。 ]]> 作者 - 演示 文檔 中繼資料 名稱 擴展包不含任何項
您可以點選下方「移除擴展包」來安全地移除此項目。]]>
- 無可用更新 選項 說明 程式庫 @@ -732,12 +730,7 @@ 注意: 任何文檔,媒體或需要這些項目才能運作的物件將會停止運作,並可能使得系統不穩定, 請小心移除。若有疑慮,請聯絡擴展包作者。]]> - 從程式庫下載更新 - 更新擴展包 - 更新說明 - 擴展包有可用的更新,您可以從程式庫網站更新。 版本 - 訪問擴展包網站 擴展包已安裝 這個擴展包無法安裝,它需要Umbraco至少是版本 %0% 移除中... diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml index a3c8abb946..39f4dd9560 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/nb.xml @@ -589,13 +589,11 @@ Vennlig hilsen Umbraco roboten Umbraco-pakker har vanligvis endelsen ".umb" eller ".zip".]]> Utvikler - Demonstrasjon Dokumentasjon Metadata Pakkenavn Pakken inneholder ingen elementer
Du kan trygt fjerne pakken fra systemet ved å klikke "avinstaller pakke" nedenfor.]]>
- Ingen oppdateringer tilgjengelig Alternativer for pakke Lesmeg for pakke Pakkebrønn @@ -604,12 +602,7 @@ Vennlig hilsen Umbraco roboten Pakken ble vellykket avinstallert Avinstaller pakke Advarsel: alle dokumenter, media, etc. som som er avhengig av elementene du sletter, vil slutte å virke, noe som kan føre til ustabilitet, så avinstaller med forsiktighet. Hvis du er i tvil, kontakt pakkeutvikleren.]]> - Last ned oppdatering fra pakkeregisteret - Oppgrader pakke - Oppgraderingsinstrukser - Det er en oppdatering tilgjengelig for denne pakken. Du kan laste den ned direkte fra pakkebrønnen. Pakkeversjon - Se pakkens nettsted Lim inn med full formattering (Anbefales ikke) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml b/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml index b61e1154b8..23da0c817c 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/zh_tw.xml @@ -714,14 +714,12 @@ 按鈕並點選該檔案。Umbraco擴展包通常有「.zip」的副檔名。 ]]> 作者 - 演示 文檔 中繼資料 名稱 擴展包不含任何項
您可以點選下方「移除擴展包」來安全地移除此項目。]]>
- 無可用更新 選項 說明 程式庫 @@ -732,12 +730,7 @@ 注意: 任何文檔,媒體或需要這些項目才能運作的物件將會停止運作,並可能使得系統不穩定, 請小心移除。若有疑慮,請聯絡擴展包作者。]]> - 從程式庫下載更新 - 更新擴展包 - 更新說明 - 擴展包有可用的更新,您可以從程式庫網站更新。 版本 - 訪問擴展包網站 擴展包已安裝 這個擴展包無法安裝,它需要Umbraco至少是版本 %0% 移除中... diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 4814a8000a..c60d035562 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -115,11 +115,18 @@ namespace Umbraco.Web.Editors return response; } + public PackageDefinition GetInstalledPackageById(int id) + { + var pack = Services.PackagingService.GetInstalledPackageById(id); + if (pack == null) throw new HttpResponseException(HttpStatusCode.NotFound); + return pack; + } + /// /// Returns all installed packages - only shows their latest versions /// /// - public IEnumerable GetInstalled() + public IEnumerable GetInstalled() { return Services.PackagingService.GetAllInstalledPackages() .GroupBy( @@ -136,19 +143,6 @@ namespace Umbraco.Web.Editors //only return the first package with this version return grouping.First(x => x.version == maxVersion).package; }) - .Select(pack => new InstalledPackageModel - { - Name = pack.Name, - Id = pack.Id, - Author = pack.Author, - Version = pack.Version, - Url = pack.Url, - License = pack.License, - LicenseUrl = pack.LicenseUrl, - Files = pack.Files, - IconUrl = pack.IconUrl, - Readme = pack.Readme - }) .ToList(); } } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 544a871720..f87f323df8 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -369,20 +369,17 @@ namespace Umbraco.Web.Editors var packageInfo = Services.PackagingService.GetCompiledPackageInfo(zipFile); + zipFile.Delete(); + + //bump cdf to be safe var clientDependencyConfig = new ClientDependencyConfiguration(Logger); var clientDependencyUpdated = clientDependencyConfig.UpdateVersionNumber( UmbracoVersion.SemanticVersion, DateTime.UtcNow, "yyyyMMdd"); - zipFile.Delete(); - var redirectUrl = ""; if (!packageInfo.PackageView.IsNullOrWhiteSpace()) { - //fixme! - throw new NotImplementedException(); - //redirectUrl = string.Format("/packages/framed/{0}", - // Uri.EscapeDataString( - // string.Format("/umbraco/developer/Packages/installer.aspx?installing=custominstaller&dir={0}&pId={1}&customControl={2}&customUrl={3}", tempDir, model.Id, ins.Control, ins.Url))); + redirectUrl = $"/packages/packages/options/{model.Id}"; } return new PackageInstallResult diff --git a/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs b/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs deleted file mode 100644 index 67bfe6fe53..0000000000 --- a/src/Umbraco.Web/Models/ContentEditing/InstalledPackageModel.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace Umbraco.Web.Models.ContentEditing -{ - [DataContract] - public class InstalledPackageModel - { - [DataMember(Name = "id")] - public int Id { get; set; } - - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "author")] - public string Author { get; set; } - - [DataMember(Name = "files")] - public IEnumerable Files { get; set; } - - [DataMember(Name = "version")] - public string Version { get; set; } - - [DataMember(Name = "url")] - public string Url { get; set; } - - [DataMember(Name = "license")] - public string License { get; set; } - - [DataMember(Name = "licenseUrl")] - public string LicenseUrl { get; set; } - - [DataMember(Name = "iconUrl")] - public string IconUrl { get; set; } - - [DataMember(Name = "readme")] - public string Readme { get; set; } - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b0142771d2..62a7d6175c 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -596,7 +596,6 @@ - From b4f2d514be5b2c14bbb5c4b2729daf407bd70176 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 16 Jan 2019 11:44:27 +0100 Subject: [PATCH 129/223] #3305 - changed new method to be internal --- src/Umbraco.Web/PublishedContentExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 0e1f75684a..d30414b3d3 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -272,7 +272,7 @@ namespace Umbraco.Web /// The content. /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// These of the inputs that has the specified culture or are invariant. - public static IEnumerable WhereHasCultureOrInvariant(this IEnumerable contents, string culture = null) + internal static IEnumerable WhereHasCultureOrInvariant(this IEnumerable contents, string culture = null) { if (contents == null) throw new ArgumentNullException(nameof(contents)); From 8347fd79a3c00d40c63c46832c3f60a07c401ae2 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 11:37:20 +0100 Subject: [PATCH 130/223] Reviewing packages PR, various fixes --- .../Services/Implement/EntityXmlSerializer.cs | 4 +- src/Umbraco.Examine/ContentValueSetBuilder.cs | 4 +- src/Umbraco.Examine/MediaValueSetBuilder.cs | 2 +- .../UmbracoExamine/IndexInitializer.cs | 2 +- src/Umbraco.Web/Composing/Current.cs | 35 --------------- .../Editors/PackageInstallController.cs | 2 +- .../InstallSteps/StarterKitDownloadStep.cs | 2 +- .../InstallSteps/StarterKitInstallStep.cs | 2 +- src/Umbraco.Web/Mvc/ContentModelBinder.cs | 2 +- .../NuCache/PublishedSnapshotService.cs | 3 ++ src/Umbraco.Web/Search/ExamineComposer.cs | 4 +- src/Umbraco.Web/UmbracoApplication.cs | 45 ++++++++++++++++++- 12 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index 1a1d2e5ab2..fd1067b3e5 100644 --- a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Services.Implement private readonly IDataTypeService _dataTypeService; private readonly IUserService _userService; private readonly ILocalizationService _localizationService; - private readonly IEnumerable _urlSegmentProviders; + private readonly UrlSegmentProviderCollection _urlSegmentProviders; public EntityXmlSerializer( IContentService contentService, @@ -31,7 +31,7 @@ namespace Umbraco.Core.Services.Implement IUserService userService, ILocalizationService localizationService, IContentTypeService contentTypeService, - IEnumerable urlSegmentProviders) + UrlSegmentProviderCollection urlSegmentProviders) { _contentTypeService = contentTypeService; _mediaService = mediaService; diff --git a/src/Umbraco.Examine/ContentValueSetBuilder.cs b/src/Umbraco.Examine/ContentValueSetBuilder.cs index d8e698cdad..a6262c53fc 100644 --- a/src/Umbraco.Examine/ContentValueSetBuilder.cs +++ b/src/Umbraco.Examine/ContentValueSetBuilder.cs @@ -13,11 +13,11 @@ namespace Umbraco.Examine ///
public class ContentValueSetBuilder : BaseValueSetBuilder, IContentValueSetBuilder, IPublishedContentValueSetBuilder { - private readonly IEnumerable _urlSegmentProviders; + private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IUserService _userService; public ContentValueSetBuilder(PropertyEditorCollection propertyEditors, - IEnumerable urlSegmentProviders, + UrlSegmentProviderCollection urlSegmentProviders, IUserService userService, bool publishedValuesOnly) : base(propertyEditors, publishedValuesOnly) diff --git a/src/Umbraco.Examine/MediaValueSetBuilder.cs b/src/Umbraco.Examine/MediaValueSetBuilder.cs index 2676093eeb..23d0414d5d 100644 --- a/src/Umbraco.Examine/MediaValueSetBuilder.cs +++ b/src/Umbraco.Examine/MediaValueSetBuilder.cs @@ -10,7 +10,7 @@ namespace Umbraco.Examine { public class MediaValueSetBuilder : BaseValueSetBuilder { - private readonly IEnumerable _urlSegmentProviders; + private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IUserService _userService; public MediaValueSetBuilder(PropertyEditorCollection propertyEditors, diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index 0b36398dd6..3019138809 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -31,7 +31,7 @@ namespace Umbraco.Tests.UmbracoExamine { public static ContentValueSetBuilder GetContentValueSetBuilder(PropertyEditorCollection propertyEditors, bool publishedValuesOnly) { - var contentValueSetBuilder = new ContentValueSetBuilder(propertyEditors, new[] { new DefaultUrlSegmentProvider() }, GetMockUserService(), publishedValuesOnly); + var contentValueSetBuilder = new ContentValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), GetMockUserService(), publishedValuesOnly); return contentValueSetBuilder; } diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 860d3ec88e..1e8f3d17f7 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -159,41 +159,6 @@ namespace Umbraco.Web.Composing #endregion - #region Web Actions - - internal static void RestartAppPool() - { - // see notes in overload - - var httpContext = HttpContext.Current; - if (httpContext != null) - { - httpContext.Application.Add("AppPoolRestarting", true); - httpContext.User = null; - } - Thread.CurrentPrincipal = null; - HttpRuntime.UnloadAppDomain(); - } - - internal static void RestartAppPool(HttpContextBase httpContext) - { - // we're going to put an application wide flag to show that the application is about to restart. - // we're doing this because if there is a script checking if the app pool is fully restarted, then - // it can check if this flag exists... if it does it means the app pool isn't restarted yet. - httpContext.Application.Add("AppPoolRestarting", true); - - // unload app domain - we must null out all identities otherwise we get serialization errors - // http://www.zpqrtbnk.net/posts/custom-iidentity-serialization-issue - httpContext.User = null; - if (HttpContext.Current != null) - HttpContext.Current.User = null; - Thread.CurrentPrincipal = null; - - HttpRuntime.UnloadAppDomain(); - } - - #endregion - #region Core Getters // proxy Core for convenience diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index dd7c4302c5..05d1e2a7a3 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -315,7 +315,7 @@ namespace Umbraco.Web.Editors var installedFiles = Services.PackagingService.InstallCompiledPackageFiles(definition, zipFile, Security.GetUserId().ResultOr(0)); //set a restarting marker and reset the app pool - Current.RestartAppPool(Request.TryGetHttpContext().Result); + UmbracoApplication.Restart(Request.TryGetHttpContext().Result); model.IsRestarting = true; diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 0349bb4ec7..641146fb4a 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.Install.InstallSteps var (packageFile, packageId) = await DownloadPackageFilesAsync(starterKitId.Value); - Current.RestartAppPool(); + UmbracoApplication.Restart(); return new InstallSetupResult(new Dictionary { diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 805041391f..8bd699f293 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.Install.InstallSteps InstallBusinessLogic(packageId); - Current.RestartAppPool(_httContext); + UmbracoApplication.Restart(_httContext); return Task.FromResult(null); } diff --git a/src/Umbraco.Web/Mvc/ContentModelBinder.cs b/src/Umbraco.Web/Mvc/ContentModelBinder.cs index b68d5a36f7..c6df52e007 100644 --- a/src/Umbraco.Web/Mvc/ContentModelBinder.cs +++ b/src/Umbraco.Web/Mvc/ContentModelBinder.cs @@ -150,7 +150,7 @@ namespace Umbraco.Web.Mvc if (context == null) AppDomain.Unload(AppDomain.CurrentDomain); else - Current.RestartAppPool(new HttpContextWrapper(context)); + UmbracoApplication.Restart(new HttpContextWrapper(context)); } throw new ModelBindingException(msg.ToString()); diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index dc8fcf8c0e..36f3472c31 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -101,6 +101,9 @@ namespace Umbraco.Web.PublishedCache.NuCache _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings; _siteDomainHelper = siteDomainHelper; + + // we need an Xml serializer here so that the member cache can support XPath, + // for members this is done by navigating the serialized-to-xml member _entitySerializer = entitySerializer; // we always want to handle repository events, configured or not diff --git a/src/Umbraco.Web/Search/ExamineComposer.cs b/src/Umbraco.Web/Search/ExamineComposer.cs index 8ee2caedee..7aab3cfd8f 100644 --- a/src/Umbraco.Web/Search/ExamineComposer.cs +++ b/src/Umbraco.Web/Search/ExamineComposer.cs @@ -33,13 +33,13 @@ namespace Umbraco.Web.Search composition.RegisterUnique(factory => new ContentValueSetBuilder( factory.GetInstance(), - factory.GetInstance>(), + factory.GetInstance(), factory.GetInstance(), true)); composition.RegisterUnique(factory => new ContentValueSetBuilder( factory.GetInstance(), - factory.GetInstance>(), + factory.GetInstance(), factory.GetInstance(), false)); composition.RegisterUnique, MediaValueSetBuilder>(); diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 136f09f83d..191fb9dcd6 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -1,4 +1,6 @@ -using Umbraco.Core; +using System.Threading; +using System.Web; +using Umbraco.Core; using Umbraco.Web.Runtime; namespace Umbraco.Web @@ -12,5 +14,46 @@ namespace Umbraco.Web { return new WebRuntime(this); } + + /// + /// Restarts the Umbraco application. + /// + public static void Restart() + { + // see notes in overload + + var httpContext = HttpContext.Current; + if (httpContext != null) + { + httpContext.Application.Add("AppPoolRestarting", true); + httpContext.User = null; + } + Thread.CurrentPrincipal = null; + HttpRuntime.UnloadAppDomain(); + } + + /// + /// Restarts the Umbraco application. + /// + public static void Restart(HttpContextBase httpContext) + { + if (httpContext != null) + { + // we're going to put an application wide flag to show that the application is about to restart. + // we're doing this because if there is a script checking if the app pool is fully restarted, then + // it can check if this flag exists... if it does it means the app pool isn't restarted yet. + httpContext.Application.Add("AppPoolRestarting", true); + + // unload app domain - we must null out all identities otherwise we get serialization errors + // http://www.zpqrtbnk.net/posts/custom-iidentity-serialization-issue + httpContext.User = null; + } + + if (HttpContext.Current != null) + HttpContext.Current.User = null; + + Thread.CurrentPrincipal = null; + HttpRuntime.UnloadAppDomain(); + } } } From 35650536c8f9956a86cb87284744e7d1283be202 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 16 Jan 2019 13:23:19 +0100 Subject: [PATCH 131/223] 3305 - Use the `VariationContext` instead of thread directly --- src/Umbraco.Web/PublishedContentExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index d30414b3d3..4efe6bc82b 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -276,7 +276,7 @@ namespace Umbraco.Web { if (contents == null) throw new ArgumentNullException(nameof(contents)); - var actualCulture = culture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; + var actualCulture = culture ?? Current.VariationContextAccessor.VariationContext.Culture; return contents.Where(x=>x.HasCulture(actualCulture) || !x.Cultures.Any()); } From a60bdf5c01f02693dbcf2a76504bf50ad8f22b6c Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 13:26:13 +0100 Subject: [PATCH 132/223] HttpContext VariationContextAccessor fails nicely --- .../PublishedContent/HttpContextVariationContextAccessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs b/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs index 70672e3796..0007b346c5 100644 --- a/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs +++ b/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.Models.PublishedContent /// public VariationContext VariationContext { - get => (VariationContext) HttpContextAccessor.HttpContext.Items[ContextKey]; + get => (VariationContext) HttpContextAccessor.HttpContext?.Items[ContextKey]; set => HttpContextAccessor.HttpContext.Items[ContextKey] = value; } } From b5bda0b6375ee0134467596589f56ee4e3490b2c Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 13:26:30 +0100 Subject: [PATCH 133/223] Some things have to be public for service events --- .../Persistence/Repositories/IDataTypeContainerRepository.cs | 2 +- .../Repositories/IDocumentTypeContainerRepository.cs | 2 +- .../Persistence/Repositories/IEntityContainerRepository.cs | 2 +- src/Umbraco.Core/Persistence/Repositories/IMacroRepository.cs | 2 +- .../Persistence/Repositories/IMediaTypeContainerRepository.cs | 2 +- src/Umbraco.Core/Services/Changes/ContentTypeChange.cs | 2 +- src/Umbraco.Core/Services/Implement/ContentTypeService.cs | 2 +- src/Umbraco.Core/Services/Implement/ContentTypeServiceBase.cs | 2 +- .../Services/Implement/ContentTypeServiceBaseOfTItemTService.cs | 2 +- .../ContentTypeServiceBaseOfTRepositoryTItemTService.cs | 2 +- src/Umbraco.Core/Services/Implement/DataTypeService.cs | 2 +- src/Umbraco.Core/Services/Implement/MacroService.cs | 2 +- src/Umbraco.Core/Services/Implement/MediaTypeService.cs | 2 +- src/Umbraco.Core/Services/Implement/MemberTypeService.cs | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/IDataTypeContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDataTypeContainerRepository.cs index 460bed71d3..57d3871e5a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDataTypeContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDataTypeContainerRepository.cs @@ -1,5 +1,5 @@ namespace Umbraco.Core.Persistence.Repositories { - interface IDataTypeContainerRepository : IEntityContainerRepository + public interface IDataTypeContainerRepository : IEntityContainerRepository { } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IDocumentTypeContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDocumentTypeContainerRepository.cs index ccf8df268d..ec8dfb9110 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDocumentTypeContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDocumentTypeContainerRepository.cs @@ -1,5 +1,5 @@ namespace Umbraco.Core.Persistence.Repositories { - interface IDocumentTypeContainerRepository : IEntityContainerRepository + public interface IDocumentTypeContainerRepository : IEntityContainerRepository { } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs index 47f0cee52b..f1c8353a0d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs @@ -2,6 +2,6 @@ namespace Umbraco.Core.Persistence.Repositories { - interface IEntityContainerRepository : IReadRepository, IWriteRepository + public interface IEntityContainerRepository : IReadRepository, IWriteRepository { } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IMacroRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IMacroRepository.cs index eefb48933e..1ed08352ed 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IMacroRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IMacroRepository.cs @@ -3,7 +3,7 @@ using Umbraco.Core.Models; namespace Umbraco.Core.Persistence.Repositories { - internal interface IMacroRepository : IReadWriteQueryRepository, IReadRepository + public interface IMacroRepository : IReadWriteQueryRepository, IReadRepository { //IEnumerable GetAll(params string[] aliases); diff --git a/src/Umbraco.Core/Persistence/Repositories/IMediaTypeContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IMediaTypeContainerRepository.cs index a1872df0cd..6a133c053a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IMediaTypeContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IMediaTypeContainerRepository.cs @@ -1,5 +1,5 @@ namespace Umbraco.Core.Persistence.Repositories { - interface IMediaTypeContainerRepository : IEntityContainerRepository + public interface IMediaTypeContainerRepository : IEntityContainerRepository { } } diff --git a/src/Umbraco.Core/Services/Changes/ContentTypeChange.cs b/src/Umbraco.Core/Services/Changes/ContentTypeChange.cs index d67f8f9200..57e1d288e4 100644 --- a/src/Umbraco.Core/Services/Changes/ContentTypeChange.cs +++ b/src/Umbraco.Core/Services/Changes/ContentTypeChange.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Models; namespace Umbraco.Core.Services.Changes { - internal class ContentTypeChange + public class ContentTypeChange where TItem : class, IContentTypeComposition { public ContentTypeChange(TItem item, ContentTypeChangeTypes changeTypes) diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeService.cs index f6498770ec..fa818496ff 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeService.cs @@ -12,7 +12,7 @@ namespace Umbraco.Core.Services.Implement /// /// Represents the ContentType Service, which is an easy access to operations involving /// - internal class ContentTypeService : ContentTypeServiceBase, IContentTypeService + public class ContentTypeService : ContentTypeServiceBase, IContentTypeService { public ContentTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IContentService contentService, IContentTypeRepository repository, IAuditRepository auditRepository, IDocumentTypeContainerRepository entityContainerRepository, IEntityRepository entityRepository) diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBase.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBase.cs index d5cdd36318..26298f171c 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBase.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Services.Implement { - internal abstract class ContentTypeServiceBase : ScopeRepositoryService + public abstract class ContentTypeServiceBase : ScopeRepositoryService { protected ContentTypeServiceBase(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory) : base(provider, logger, eventMessagesFactory) diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs index 33fb9a0894..f4457e0991 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Services.Changes; namespace Umbraco.Core.Services.Implement { - internal abstract class ContentTypeServiceBase : ContentTypeServiceBase + public abstract class ContentTypeServiceBase : ContentTypeServiceBase where TItem : class, IContentTypeComposition where TService : class, IContentTypeServiceBase { diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index be4f719bb1..8189c6524e 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -13,7 +13,7 @@ using Umbraco.Core.Services.Changes; namespace Umbraco.Core.Services.Implement { - internal abstract class ContentTypeServiceBase : ContentTypeServiceBase, IContentTypeServiceBase + public abstract class ContentTypeServiceBase : ContentTypeServiceBase, IContentTypeServiceBase where TRepository : IContentTypeRepositoryBase where TItem : class, IContentTypeComposition where TService : class, IContentTypeServiceBase diff --git a/src/Umbraco.Core/Services/Implement/DataTypeService.cs b/src/Umbraco.Core/Services/Implement/DataTypeService.cs index 79ca851de9..84d44649da 100644 --- a/src/Umbraco.Core/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Core/Services/Implement/DataTypeService.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Services.Implement /// /// Represents the DataType Service, which is an easy access to operations involving /// - internal class DataTypeService : ScopeRepositoryService, IDataTypeService + public class DataTypeService : ScopeRepositoryService, IDataTypeService { private readonly IDataTypeRepository _dataTypeRepository; private readonly IDataTypeContainerRepository _dataTypeContainerRepository; diff --git a/src/Umbraco.Core/Services/Implement/MacroService.cs b/src/Umbraco.Core/Services/Implement/MacroService.cs index 5176e2eb22..d4f2d95bbb 100644 --- a/src/Umbraco.Core/Services/Implement/MacroService.cs +++ b/src/Umbraco.Core/Services/Implement/MacroService.cs @@ -12,7 +12,7 @@ namespace Umbraco.Core.Services.Implement /// /// Represents the Macro Service, which is an easy access to operations involving /// - internal class MacroService : ScopeRepositoryService, IMacroService + public class MacroService : ScopeRepositoryService, IMacroService { private readonly IMacroRepository _macroRepository; private readonly IAuditRepository _auditRepository; diff --git a/src/Umbraco.Core/Services/Implement/MediaTypeService.cs b/src/Umbraco.Core/Services/Implement/MediaTypeService.cs index fe8c78e137..8cb69a655d 100644 --- a/src/Umbraco.Core/Services/Implement/MediaTypeService.cs +++ b/src/Umbraco.Core/Services/Implement/MediaTypeService.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Services.Implement { - internal class MediaTypeService : ContentTypeServiceBase, IMediaTypeService + public class MediaTypeService : ContentTypeServiceBase, IMediaTypeService { public MediaTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMediaService mediaService, IMediaTypeRepository mediaTypeRepository, IAuditRepository auditRepository, IMediaTypeContainerRepository entityContainerRepository, diff --git a/src/Umbraco.Core/Services/Implement/MemberTypeService.cs b/src/Umbraco.Core/Services/Implement/MemberTypeService.cs index 6cc7d03cfb..05f32dc99c 100644 --- a/src/Umbraco.Core/Services/Implement/MemberTypeService.cs +++ b/src/Umbraco.Core/Services/Implement/MemberTypeService.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Services.Implement { - internal class MemberTypeService : ContentTypeServiceBase, IMemberTypeService + public class MemberTypeService : ContentTypeServiceBase, IMemberTypeService { private readonly IMemberTypeRepository _memberTypeRepository; From 9f41457f45f37011d08175af7ca223ff34534150 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 13:44:19 +0100 Subject: [PATCH 134/223] Public composition.UrlProviders --- src/Umbraco.Web/CompositionExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs index f72c876a61..d33b1addf5 100644 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ b/src/Umbraco.Web/CompositionExtensions.cs @@ -81,7 +81,7 @@ namespace Umbraco.Core.Components /// Gets the url providers collection builder. /// /// The composition. - internal static UrlProviderCollectionBuilder UrlProviders(this Composition composition) + public static UrlProviderCollectionBuilder UrlProviders(this Composition composition) => composition.WithCollectionBuilder(); #endregion From 7bb358888980bdcd8d605214b611ba7bd22c0712 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 16 Jan 2019 23:53:10 +1100 Subject: [PATCH 135/223] Adds the whole package definition to the scope model for devs to use, adds a custom query string parameter when redirecting to the angular view after install (so devs know its a new install) --- .../src/views/packages/edit.controller.js | 2 +- .../src/views/packages/options.controller.js | 6 +++++- .../src/views/packages/overview.controller.js | 14 +++++++------- .../packages/views/install-local.controller.js | 10 ++-------- .../views/packages/views/installed.controller.js | 5 +++-- .../src/views/packages/views/repo.controller.js | 6 ++---- 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index ca20b33a3e..bed3341c6b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -130,7 +130,7 @@ } function back() { - $location.path("packages/packages/created").search("create", null); + $location.path("packages/packages/created").search("create", null).search("packageId", null); } function createOrUpdatePackage(editPackageForm) { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js index 8ffd282e0d..4fdf6488a0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/options.controller.js @@ -15,6 +15,10 @@ packageResource.getInstalledById(packageId).then(pck => { vm.package = pck; + + //set the $scope too, packages can then access this if they wanted from their own scope or parent scope + $scope.package = pck; + vm.loading = false; //make sure the packageView is formatted as a virtual path @@ -30,7 +34,7 @@ } function back() { - $location.path("packages/packages/installed"); + $location.path("packages/packages/installed").search("packageId", null); } diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js index f4c1ab9de4..e48271aa23 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/overview.controller.js @@ -4,26 +4,26 @@ function PackagesOverviewController($scope, $location, $routeParams, localStorageService) { //Hack! - // if there is a cookie value for packageInstallUri then we need to redirect there, + // if there is a local storage value for packageInstallData then we need to redirect there, // the issue is that we still have webforms and we cannot go to a hash location and then window.reload // because it will double load it. // we will refresh and then navigate there. - let installPackageUri = localStorageService.get("packageInstallUri"); + let packageInstallData = localStorageService.get("packageInstallData"); let packageUri = $routeParams.method; - if (installPackageUri) { - localStorageService.remove("packageInstallUri"); + if (packageInstallData) { + localStorageService.remove("packageInstallData"); } - if (installPackageUri && installPackageUri !== "installed") { + if (packageInstallData && packageInstallData !== "installed" && packageInstallData.postInstallationPath) { //navigate to the custom installer screen, if it is just "installed" it means there is no custom installer screen - $location.path(installPackageUri).search(""); + $location.path(packageInstallData.postInstallationPath).search("packageId", packageInstallData.id); } else { var vm = this; - packageUri = installPackageUri ? installPackageUri : packageUri; //use the path stored in storage over the one in the current path + packageUri = packageInstallData ? packageInstallData : packageUri; //use the path stored in storage over the one in the current path vm.page = {}; vm.page.name = "Packages"; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js index 17b417de48..0d9341243b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js @@ -184,14 +184,8 @@ installError) .then(function (result) { - if (result.postInstallationPath) { - //Put the redirect Uri in a cookie so we can use after reloading - localStorageService.set("packageInstallUri", result.postInstallationPath); - } - else { - //set to a constant value so it knows to just go to the installed view - localStorageService.set("packageInstallUri", "installed"); - } + //Put the package data in local storage so we can use after reloading + localStorageService.set("packageInstallData", result); vm.installState.status = labels.installStateCompleted; vm.installCompleted = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js index 3b6422ace4..ddfee19ac1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.controller.js @@ -36,7 +36,8 @@ } function packageOptions(pck) { - $location.path("packages/packages/options/" + pck.id); + $location.path("packages/packages/options/" + pck.id) + .search("packageId", null); //ensure the installId flag is gone, it's only available on first install } function confirmUninstall(pck) { @@ -56,7 +57,7 @@ vm.installState.progress = "100"; //set this flag so that on refresh it shows the installed packages list - localStorageService.set("packageInstallUri", "installed"); + localStorageService.set("packageInstallData", "installed"); //reload on next digest (after cookie) $timeout(function () { diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js index b77326d2fc..dc3e67db15 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js @@ -257,10 +257,8 @@ error) .then(function (result) { - if (result.postInstallationPath) { - //Put the redirect Uri in a cookie so we can use after reloading - localStorageService.set("packageInstallUri", result.postInstallationPath); - } + //Put the package data in local storage so we can use after reloading + localStorageService.set("packageInstallData", result); vm.installState.status = labels.installStateCompleted; vm.installCompleted = true; From ddcead26582daa2d87b7eeaa74f5b5e475a57eb1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 00:29:43 +1100 Subject: [PATCH 136/223] Updates EntityController to support stylesheets, languages and dictionary items GetAll so we can use it for the packager without worrying about security access to sections --- .../src/views/packages/edit.controller.js | 8 +-- .../Editors/DictionaryController.cs | 4 +- src/Umbraco.Web/Editors/EntityController.cs | 57 +++++++++++++++++-- .../ContentEditing/UmbracoEntityTypes.cs | 7 ++- .../Models/Mapping/CodeFileMapperProfile.cs | 12 ++++ .../Models/Mapping/DictionaryMapperProfile.cs | 12 ++++ .../Models/Mapping/LanguageMapperProfile.cs | 12 ++++ 7 files changed, 99 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index bed3341c6b..0a44192041 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($scope, $location, $routeParams, umbRequestHelper, entityResource, stylesheetResource, languageResource, packageResource, dictionaryResource, editorService, formHelper) { + function EditController($scope, $location, $routeParams, umbRequestHelper, entityResource, packageResource, editorService, formHelper) { const vm = this; @@ -73,7 +73,7 @@ }); // get all stylesheets - stylesheetResource.getAll().then(stylesheets => { + entityResource.getAll("Stylesheet").then(stylesheets => { vm.stylesheets = stylesheets; }); @@ -87,7 +87,7 @@ }); // get all languages - languageResource.getAll().then(languages => { + entityResource.getAll("Language").then(languages => { // a package stores the id as a string so we // need to convert all ids to string for comparison languages.forEach(language => { @@ -97,7 +97,7 @@ }); // get all dictionary items - dictionaryResource.getList().then(dictionaryItems => { + entityResource.getAll("DictionaryItem").then(dictionaryItems => { // a package stores the id as a string so we // need to convert all ids to string for comparison dictionaryItems.forEach(dictionaryItem => { diff --git a/src/Umbraco.Web/Editors/DictionaryController.cs b/src/Umbraco.Web/Editors/DictionaryController.cs index cd3141c7b9..9d01cc9d64 100644 --- a/src/Umbraco.Web/Editors/DictionaryController.cs +++ b/src/Umbraco.Web/Editors/DictionaryController.cs @@ -219,7 +219,7 @@ namespace Umbraco.Web.Editors /// /// The list. /// - private void GetChildItemsForList(IDictionaryItem dictionaryItem, int level, List list) + private void GetChildItemsForList(IDictionaryItem dictionaryItem, int level, ICollection list) { foreach (var childItem in Services.LocalizationService.GetDictionaryItemChildren(dictionaryItem.Key).OrderBy(ItemSort())) { @@ -231,6 +231,6 @@ namespace Umbraco.Web.Editors } } - private Func ItemSort() => item => item.ItemKey; + private static Func ItemSort() => item => item.ItemKey; } } diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 993489855f..396615a339 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -839,8 +839,6 @@ namespace Umbraco.Web.Editors return UmbracoObjectTypes.MediaType; case UmbracoEntityTypes.DocumentType: return UmbracoObjectTypes.DocumentType; - case UmbracoEntityTypes.Stylesheet: - return UmbracoObjectTypes.Stylesheet; case UmbracoEntityTypes.Member: return UmbracoObjectTypes.Member; case UmbracoEntityTypes.DataType: @@ -912,13 +910,31 @@ namespace Umbraco.Web.Editors case UmbracoEntityTypes.User: - long total; - var users = Services.UserService.GetAll(0, int.MaxValue, out total); + var users = Services.UserService.GetAll(0, int.MaxValue, out _); var filteredUsers = ExecutePostFilter(users, postFilter, postFilterParams); return Mapper.Map, IEnumerable>(filteredUsers); - case UmbracoEntityTypes.Domain: + case UmbracoEntityTypes.Stylesheet: + + if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0)) + throw new NotSupportedException("Filtering on stylesheets is not currently supported"); + + return Services.FileService.GetStylesheets().Select(Mapper.Map); + case UmbracoEntityTypes.Language: + + if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0)) + throw new NotSupportedException("Filtering on languages is not currently supported"); + + return Services.LocalizationService.GetAllLanguages().Select(Mapper.Map); + case UmbracoEntityTypes.DictionaryItem: + + if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0)) + throw new NotSupportedException("Filtering on languages is not currently supported"); + + return GetAllDictionaryItems(); + + case UmbracoEntityTypes.Domain: default: throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); } @@ -937,5 +953,36 @@ namespace Umbraco.Web.Editors } return entities; } + + + #region Methods to get all dictionary items + private IEnumerable GetAllDictionaryItems() + { + var list = new List(); + + foreach (var dictionaryItem in Services.LocalizationService.GetRootDictionaryItems().OrderBy(DictionaryItemSort())) + { + var item = Mapper.Map(dictionaryItem); + list.Add(item); + GetChildItemsForList(dictionaryItem, list); + } + + return list; + } + + private static Func DictionaryItemSort() => item => item.ItemKey; + + private void GetChildItemsForList(IDictionaryItem dictionaryItem, ICollection list) + { + foreach (var childItem in Services.LocalizationService.GetDictionaryItemChildren(dictionaryItem.Key).OrderBy(DictionaryItemSort())) + { + var item = Mapper.Map(childItem); + list.Add(item); + + GetChildItemsForList(childItem, list); + } + } + #endregion + } } diff --git a/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs b/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs index 04d06845d9..fcf7271673 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UmbracoEntityTypes.cs @@ -86,8 +86,11 @@ namespace Umbraco.Web.Models.ContentEditing /// /// Property Group /// - PropertyGroup + PropertyGroup, - //TODO: Dictionary? + /// + /// Dictionary Item + /// + DictionaryItem } } diff --git a/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs index 94c43f8f11..b3f5f0374c 100644 --- a/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs @@ -9,6 +9,18 @@ namespace Umbraco.Web.Models.Mapping { public CodeFileMapperProfile() { + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(sheet => sheet.Id)) + .ForMember(dest => dest.Alias, opt => opt.MapFrom(sheet => sheet.Alias)) + .ForMember(dest => dest.Key, opt => opt.MapFrom(sheet => sheet.Key)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(sheet => sheet.Name)) + .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.Path, opt => opt.MapFrom(sheet => sheet.Path)) + .ForMember(dest => dest.Trashed, opt => opt.Ignore()) + .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) + .ForMember(dest => dest.Udi, opt => opt.Ignore()) + .ForMember(dest => dest.Icon, opt => opt.Ignore()); + CreateMap() .ForMember(dest => dest.FileType, opt => opt.Ignore()) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/DictionaryMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/DictionaryMapperProfile.cs index ebd675f572..b3af04603c 100644 --- a/src/Umbraco.Web/Models/Mapping/DictionaryMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/DictionaryMapperProfile.cs @@ -17,6 +17,18 @@ namespace Umbraco.Web.Models.Mapping { public DictionaryMapperProfile(ILocalizationService localizationService) { + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(sheet => sheet.Id)) + .ForMember(dest => dest.Alias, opt => opt.MapFrom(sheet => sheet.ItemKey)) + .ForMember(dest => dest.Key, opt => opt.MapFrom(sheet => sheet.Key)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(sheet => sheet.ItemKey)) + .ForMember(dest => dest.ParentId, opt => opt.Ignore()) + .ForMember(dest => dest.Path, opt => opt.Ignore()) + .ForMember(dest => dest.Trashed, opt => opt.Ignore()) + .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) + .ForMember(dest => dest.Udi, opt => opt.Ignore()) + .ForMember(dest => dest.Icon, opt => opt.Ignore()); + CreateMap() .ForMember(x => x.Translations, expression => expression.Ignore()) .ForMember(x => x.Notifications, expression => expression.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs index f820d5ae54..ea29b671a6 100644 --- a/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs @@ -12,6 +12,18 @@ namespace Umbraco.Web.Models.Mapping { public LanguageMapperProfile() { + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(x => x.Id)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(x => x.CultureName)) + .ForMember(dest => dest.Key, opt => opt.MapFrom(x => x.Key)) + .ForMember(dest => dest.Alias, opt => opt.MapFrom(x => x.IsoCode)) + .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.Path, opt => opt.Ignore()) + .ForMember(dest => dest.Trashed, opt => opt.Ignore()) + .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) + .ForMember(dest => dest.Udi, opt => opt.Ignore()) + .ForMember(dest => dest.Icon, opt => opt.Ignore()); + CreateMap() .ForMember(l => l.Name, expression => expression.MapFrom(x => x.CultureInfo.DisplayName)); From 3ed1b44710d21b8a5f3b9c6321020541689dafb3 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 15:21:10 +0100 Subject: [PATCH 137/223] Try to bugfix a failing test --- .../Packaging/PackageInstallationTest.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index d944b638ad..5e33538f17 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -60,7 +60,7 @@ namespace Umbraco.Tests.Packaging public void Can_Read_Compiled_Package_1() { var package = PackageInstallation.ReadPackage( - //this is where our test zip file is + //this is where our test zip file is new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); Assert.IsNotNull(package); Assert.AreEqual(1, package.Files.Count); @@ -83,7 +83,7 @@ namespace Umbraco.Tests.Packaging public void Can_Read_Compiled_Package_2() { var package = PackageInstallation.ReadPackage( - //this is where our test zip file is + //this is where our test zip file is new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), HelloPackage))); Assert.IsNotNull(package); Assert.AreEqual(0, package.Files.Count); @@ -110,18 +110,22 @@ namespace Umbraco.Tests.Packaging { //copy a file to the same path that the package will install so we can detect file conflicts var path = IOHelper.MapPath("~/" + _testBaseFolder); + Console.WriteLine(path); + var filePath = Path.Combine(path, "bin", "Auros.DocumentTypePicker.dll"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)); File.WriteAllText(filePath, "test"); - var preInstallWarnings = PackageInstallation.ReadPackage( - //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))) - .Warnings; + //this is where our test zip file is + var packageFile = Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage); + Console.WriteLine(packageFile); + + var package = PackageInstallation.ReadPackage(new FileInfo(packageFile)); + var preInstallWarnings = package.Warnings; Assert.IsNotNull(preInstallWarnings); - Assert.AreEqual(preInstallWarnings.FilesReplaced.Count(), 1); - Assert.AreEqual(preInstallWarnings.FilesReplaced.First(), "bin\\Auros.DocumentTypePicker.dll"); + Assert.AreEqual(1, preInstallWarnings.FilesReplaced.Count()); + Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", preInstallWarnings.FilesReplaced.First()); //TODO: More Asserts } @@ -130,7 +134,7 @@ namespace Umbraco.Tests.Packaging public void Install_Files() { var package = PackageInstallation.ReadPackage( - //this is where our test zip file is + //this is where our test zip file is new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); var def = PackageDefinition.FromCompiledPackage(package); @@ -152,7 +156,7 @@ namespace Umbraco.Tests.Packaging public void Install_Data() { var package = PackageInstallation.ReadPackage( - //this is where our test zip file is + //this is where our test zip file is new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; @@ -161,7 +165,7 @@ namespace Umbraco.Tests.Packaging var summary = PackageInstallation.InstallPackageData(def, package, -1); Assert.AreEqual(1, summary.DataTypesInstalled.Count()); - + //make sure the def is updated too Assert.AreEqual(summary.DataTypesInstalled.Count(), def.DataTypes.Count); From 664a892fd5073a37a9d10bb4a5ea57c0e29df948 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 16 Jan 2019 15:25:42 +0100 Subject: [PATCH 138/223] 3305 - fixed tests --- .../Testing/Objects/Accessors/TestVariationContextAccessor.cs | 2 +- .../PublishedCache/XmlPublishedCache/XmlPublishedContent.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs b/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs index 3c7377f2cc..4b56799fa4 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs +++ b/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs @@ -12,6 +12,6 @@ namespace Umbraco.Tests.Testing.Objects.Accessors { get; set; - } + } = new VariationContext(); } } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index efd4535bd4..d8436c05b5 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -138,7 +138,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public override PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException(); - public override IReadOnlyDictionary Cultures => throw new NotSupportedException(); + public override IReadOnlyDictionary Cultures => new Dictionary(); public override string WriterName { From 899bb812aac24d52ff1f014e2d1b2fd54a257dd9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 01:42:56 +1100 Subject: [PATCH 139/223] Creates RuntimeStateOptions and pre-loads the error page on the installer --- src/Umbraco.Core/RuntimeState.cs | 12 ++---- src/Umbraco.Core/RuntimeStateOptions.cs | 40 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../src/installer/installer.service.js | 33 +++++++++------ 4 files changed, 64 insertions(+), 22 deletions(-) create mode 100644 src/Umbraco.Core/RuntimeStateOptions.cs diff --git a/src/Umbraco.Core/RuntimeState.cs b/src/Umbraco.Core/RuntimeState.cs index e344a67920..85e8c7370d 100644 --- a/src/Umbraco.Core/RuntimeState.cs +++ b/src/Umbraco.Core/RuntimeState.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Configuration; using System.Threading; using System.Web; using Semver; @@ -133,11 +132,6 @@ namespace Umbraco.Core /// public BootFailedException BootFailedException { get; internal set; } - // currently configured via app settings - private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing; - private bool InstallMissingDatabase { get; } = BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false); - private bool InstallEmptyDatabase { get; } = BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false); - /// /// Determines the runtime level. /// @@ -185,7 +179,7 @@ namespace Umbraco.Core // else, keep going, // anything other than install wants a database - see if we can connect // (since this is an already existing database, assume localdb is ready) - var tries = InstallMissingDatabase ? 2 : 5; + var tries = RuntimeStateOptions.InstallMissingDatabase ? 2 : 5; for (var i = 0;;) { connect = databaseFactory.CanConnect; @@ -199,7 +193,7 @@ namespace Umbraco.Core // cannot connect to configured database, this is bad, fail logger.Debug("Could not connect to database."); - if (InstallMissingDatabase) + if (RuntimeStateOptions.InstallMissingDatabase) { // ok to install on a configured but missing database Level = RuntimeLevel.Install; @@ -228,7 +222,7 @@ namespace Umbraco.Core // can connect to the database but cannot check the upgrade state... oops logger.Warn(e, "Could not check the upgrade state."); - if (InstallEmptyDatabase) + if (RuntimeStateOptions.InstallEmptyDatabase) { // ok to install on an empty database Level = RuntimeLevel.Install; diff --git a/src/Umbraco.Core/RuntimeStateOptions.cs b/src/Umbraco.Core/RuntimeStateOptions.cs new file mode 100644 index 0000000000..9262a8a990 --- /dev/null +++ b/src/Umbraco.Core/RuntimeStateOptions.cs @@ -0,0 +1,40 @@ +using System.Configuration; + +namespace Umbraco.Core +{ + /// + /// Allows configuration of the in PreApplicationStart or in appSettings + /// + public static class RuntimeStateOptions + { + // configured statically or via app settings + private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing; + + /// + /// If true the RuntimeState will continue the installation sequence when a database is missing + /// + /// + /// In this case it will be up to the implementor that is setting this value to true to take over the bootup/installation sequence + /// + public static bool InstallMissingDatabase + { + get => _installEmptyDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false); + set => _installEmptyDatabase = value; + } + + /// + /// If true the RuntimeState will continue the installation sequence when a database is available but is empty + /// + /// + /// In this case it will be up to the implementor that is setting this value to true to take over the bootup/installation sequence + /// + public static bool InstallEmptyDatabase + { + get => _installMissingDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false); + set => _installMissingDatabase = value; + } + + private static bool? _installMissingDatabase; + private static bool? _installEmptyDatabase; + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 50cc36d7b9..2236854351 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -512,6 +512,7 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.service.js b/src/Umbraco.Web.UI.Client/src/installer/installer.service.js index a8e0530417..cc92935b4d 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer.service.js +++ b/src/Umbraco.Web.UI.Client/src/installer/installer.service.js @@ -1,4 +1,4 @@ -angular.module("umbraco.install").factory('installerService', function($rootScope, $q, $timeout, $http, $location, $log){ +angular.module("umbraco.install").factory('installerService', function ($rootScope, $q, $timeout, $http, $templateRequest){ var _status = { index: 0, @@ -106,19 +106,26 @@ angular.module("umbraco.install").factory('installerService', function($rootScop //loads the needed steps and sets the intial state init : function(){ service.status.loading = true; - if(!_status.all){ - service.getSteps().then(function(response){ - service.status.steps = response.data.steps; - service.status.index = 0; - _installerModel.installId = response.data.installId; - service.findNextStep(); + if (!_status.all) { + //pre-load the error page, if an error occurs, the page might not be able to load + // so we want to make sure it's available in the templatecache first + $templateRequest("views/install/error.html").then(x => { + service.getSteps().then(response => { + service.status.steps = response.data.steps; + service.status.index = 0; + _installerModel.installId = response.data.installId; + service.findNextStep(); - $timeout(function(){ - service.status.loading = false; - service.status.configuring = true; - }, 2000); - }); - } + $timeout(function() { + service.status.loading = false; + service.status.configuring = true; + }, + 2000); + }); + }); + + + } }, //loads available packages from our.umbraco.com From b6a8ad1b6e9827c0a211b51af28e67c98cc36c94 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 16 Jan 2019 16:21:19 +0100 Subject: [PATCH 140/223] #3417 load available partial views from api --- .../src/common/resources/macro.resource.js | 7 + .../views/macros/macros.edit.controller.js | 144 +++++++++++------- src/Umbraco.Web/Editors/MacrosController.cs | 124 ++++++++++++++- 3 files changed, 215 insertions(+), 60 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index 9f22465757..237a361f7e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -87,6 +87,13 @@ function macroResource($q, $http, umbRequestHelper) { ), 'Failed to create macro "' + name + '"' ); + }, + + getPartialViews: function() { + return umbRequestHelper.resourcePromise( + $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetPartialViews"), + "Failed to get partial views") + ); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js index 81c699a05f..fa3a4e45a5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js @@ -6,77 +6,25 @@ * @description * The controller for editing macros. */ -function MacrosEditController($scope, $routeParams, macroResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService, angularHelper) { +function MacrosEditController($scope, $q, $routeParams, macroResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService, angularHelper) { var vm = this; + vm.promises = {}; + vm.page = {}; vm.page.loading = false; vm.page.saveButtonState = "init"; vm.page.menu = {} - vm.save = saveMacro; - vm.toggle = toggleValue; - - - init(); - - function init() { - vm.page.loading = true; - - - vm.page.navigation = [ - { - "name": "Settings", - "alias": "settings", - "icon": "icon-settings", - "view": "views/macros/views/settings.html", - "active": true - }, - { - "name": "Parameters", - "alias": "parameters", - "icon": "icon-list", - "view": "views/macros/views/parameters.html" - } - ]; - - vm.macro = { - "name": "Test macro", - "alias": "testMacro", - "id": 1, - "key": "unique key goes here", - "useInEditor": true, - "renderInEditor": false, - "cachePeriod": 2400, - "cacheByPage": true, - "cacheByUser": false, - "view": "Second", - "parameters": [ - { - "key": "title", - "label": "Label", - "editor": "editor" - }, - { - "key": "link", - "label": "Link", - "editor": "Link picker" - } - ] - } - - vm.views = ['First', 'Second', 'Third']; - - vm.parameterEditors = ['editor', 'Link picker', 'Image picker']; - - vm.page.loading = false; - } + function toggleValue(key) { vm.macro[key] = !vm.macro[key]; } + vm.toggle = toggleValue; + function saveMacro() { vm.page.saveButtonState = "busy"; @@ -98,6 +46,8 @@ function MacrosEditController($scope, $routeParams, macroResource, editorState, } } + vm.save = saveMacro; + function setFormDirty() { var currentForm = angularHelper.getCurrentForm($scope); @@ -108,6 +58,84 @@ function MacrosEditController($scope, $routeParams, macroResource, editorState, } vm.setDirty = setFormDirty; + + function getPartialViews() { + var deferred = $q.defer(); + + macroResource.getPartialViews().then(function (data) { + deferred.resolve(data); + }, function () { + deferred.reject(); + }); + + return deferred.promise; + } + + function init() { + vm.page.loading = true; + + vm.promises['partialViews'] = getPartialViews(); + + $q.all(vm.promises).then(function (values) { + var keys = Object.keys(values); + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + + if (keys[i] === 'partialViews') { + vm.views = values[key]; + } + } + + vm.page.loading = false; + }); + + + vm.page.navigation = [ + { + "name": "Settings", + "alias": "settings", + "icon": "icon-settings", + "view": "views/macros/views/settings.html", + "active": true + }, + { + "name": "Parameters", + "alias": "parameters", + "icon": "icon-list", + "view": "views/macros/views/parameters.html" + } + ]; + + vm.macro = { + "name": "Test macro", + "alias": "testMacro", + "id": 1, + "key": "unique key goes here", + "useInEditor": true, + "renderInEditor": false, + "cachePeriod": 2400, + "cacheByPage": true, + "cacheByUser": false, + "view": "Second", + "parameters": [ + { + "key": "title", + "label": "Label", + "editor": "editor" + }, + { + "key": "link", + "label": "Link", + "editor": "Link picker" + } + ] + } + + vm.parameterEditors = ['editor', 'Link picker', 'Image picker']; + } + + init(); } angular.module("umbraco").controller("Umbraco.Editors.Macros.EditController", MacrosEditController); diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index f1d949231e..553924c3e6 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -14,6 +14,12 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Editors { + using System.Collections.Generic; + using System.IO; + using System.Linq; + + using Umbraco.Core.IO; + /// /// The API controller used for editing dictionary items /// @@ -48,7 +54,7 @@ namespace Umbraco.Web.Editors try { - var macro = new Macro { Alias = alias, Name = name, MacroSource = string.Empty}; + var macro = new Macro { Alias = alias, Name = name, MacroSource = string.Empty }; this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); @@ -58,7 +64,121 @@ namespace Umbraco.Web.Editors { this.Logger.Error(exception, "Error creating macro"); return Request.CreateNotificationValidationErrorResponse("Error creating dictionary item"); - } + } + } + + /// + /// Gets a list of available macro partials + /// + /// + /// The . + /// + public HttpResponseMessage GetPartialViews() + { + var views = new List(); + + views.AddRange(this.FindPartialViewsFiles()); + + return this.Request.CreateResponse(HttpStatusCode.OK, views); + } + + /// + /// Finds all the macro partials + /// + /// + /// The . + /// + private IEnumerable FindPartialViewsFiles() + { + var files = new List(); + + files.AddRange(this.FindPartialViewFilesInViewsFolder()); + files.AddRange(this.FindPartialViewFilesInPluginFolders()); + + return files; + } + + /// + /// Finds all macro partials in the views folder + /// + /// + /// The . + /// + private IEnumerable FindPartialViewFilesInViewsFolder() + { + var partialsDir = IOHelper.MapPath(SystemDirectories.MacroPartials); + + return this.FindPartialViewFilesInFolder( + partialsDir, + partialsDir, + SystemDirectories.MacroPartials); + } + + /// + /// Finds partial view files in app plugin folders. + /// + /// + /// The . + /// + private IEnumerable FindPartialViewFilesInPluginFolders() + { + var files = new List(); + + var appPluginsFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins)); + + if (!appPluginsFolder.Exists) + { + return files; + } + + foreach (var directory in appPluginsFolder.GetDirectories()) + { + var viewsFolder = directory.GetDirectories("Views"); + if (viewsFolder.Any()) + { + var macroPartials = viewsFolder.First().GetDirectories("MacroPartials"); + if (macroPartials.Any()) + { + files.AddRange(this.FindPartialViewFilesInFolder(macroPartials.First().FullName, macroPartials.First().FullName, SystemDirectories.AppPlugins + "/" + directory.Name + "/Views/MacroPartials")); + } + } + } + + return files; + } + + /// + /// Finds all partial views in a folder and subfolders + /// + /// + /// The org path. + /// + /// + /// The path. + /// + /// + /// The prefix virtual path. + /// + /// + /// The . + /// + private IEnumerable FindPartialViewFilesInFolder(string orgPath, string path, string prefixVirtualPath) + { + var files = new List(); + var dirInfo = new DirectoryInfo(path); + + foreach (var dir in dirInfo.GetDirectories()) + { + files.AddRange(this.FindPartialViewFilesInFolder(orgPath, path + "/" + dir.Name, prefixVirtualPath)); + } + + var fileInfo = dirInfo.GetFiles("*.*"); + + files.AddRange( + fileInfo.Select(file => + prefixVirtualPath.TrimEnd('/') + "/" + (path.Replace(orgPath, string.Empty).Trim('/') + "/" + file.Name).Trim('/'))); + + return files; } } } From c0e62c4c5fa39ae3858eb5d74f0b3f417aeed10e Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 16 Jan 2019 16:37:33 +0100 Subject: [PATCH 141/223] #3417 retreive a list with parameter editors from API --- .../src/common/resources/macro.resource.js | 7 +++++++ .../macros/infiniteeditors/parameter.html | 2 +- .../views/macros/macros.edit.controller.js | 21 ++++++++++++++++--- src/Umbraco.Web/Editors/MacrosController.cs | 12 +++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index 237a361f7e..5313eadcaa 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -94,6 +94,13 @@ function macroResource($q, $http, umbRequestHelper) { $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetPartialViews"), "Failed to get partial views") ); + }, + + getParameterEditors: function () { + return umbRequestHelper.resourcePromise( + $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetParameterEditors"), + "Failed to get parameter editors") + ); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html index ac01fa588e..bf9dbf86a3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html @@ -26,7 +26,7 @@ - + diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js index fa3a4e45a5..f8cde110e6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js @@ -71,10 +71,23 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta return deferred.promise; } + function getParameterEditors() { + var deferred = $q.defer(); + + macroResource.getParameterEditors().then(function (data) { + deferred.resolve(data); + }, function () { + deferred.reject(); + }); + + return deferred.promise; + } + function init() { vm.page.loading = true; vm.promises['partialViews'] = getPartialViews(); + vm.promises['parameterEditors'] = getParameterEditors(); $q.all(vm.promises).then(function (values) { var keys = Object.keys(values); @@ -85,6 +98,10 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta if (keys[i] === 'partialViews') { vm.views = values[key]; } + + if (keys[i] === 'parameterEditors') { + vm.parameterEditors = values[key]; + } } vm.page.loading = false; @@ -130,9 +147,7 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta "editor": "Link picker" } ] - } - - vm.parameterEditors = ['editor', 'Link picker', 'Image picker']; + } } init(); diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 553924c3e6..6e2d032ad4 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -19,6 +19,7 @@ namespace Umbraco.Web.Editors using System.Linq; using Umbraco.Core.IO; + using Umbraco.Web.Composing; /// /// The API controller used for editing dictionary items @@ -82,6 +83,17 @@ namespace Umbraco.Web.Editors return this.Request.CreateResponse(HttpStatusCode.OK, views); } + /// + /// Gets the available parameter editors + /// + /// + /// The . + /// + public HttpResponseMessage GetParameterEditors() + { + return this.Request.CreateResponse(HttpStatusCode.OK, Current.ParameterEditors); + } + /// /// Finds all the macro partials /// From 5f7bf3a211d920c8e2efca17955ecc457c1d9151 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 16 Jan 2019 17:03:36 +0100 Subject: [PATCH 142/223] Ignore failing test --- src/Umbraco.Tests/Packaging/PackageInstallationTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 5e33538f17..2b9e50e9e5 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -106,6 +106,7 @@ namespace Umbraco.Tests.Packaging } [Test] + [Explicit("Will fail on CI?")] public void Can_Read_Compiled_Package_Warnings() { //copy a file to the same path that the package will install so we can detect file conflicts From 67c571fb289bf7cbf2efa4f739f94a6221b8e958 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 10:56:24 +1100 Subject: [PATCH 143/223] Fixes tests --- src/Umbraco.Core/Composing/Composers/ServicesComposer.cs | 3 +-- src/Umbraco.Core/Packaging/PackageInstallation.cs | 9 ++------- src/Umbraco.Tests/Packaging/PackageInstallationTest.cs | 4 +--- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 1 - 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index bd07123fb2..8c9ccd1088 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -67,12 +67,11 @@ namespace Umbraco.Core.Composing.Composers composition.RegisterUnique(factory => CreatePackageRepository(factory, "installedPackages.config")); composition.RegisterUnique(); composition.RegisterUnique(); - var appRoot = new DirectoryInfo(IOHelper.GetRootDirectorySafe()); composition.RegisterUnique(factory => //factory required because we need to pass in a string path new PackageInstallation( factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - appRoot, appRoot)); + new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); //TODO: These are replaced in the web project - we need to declare them so that // something is wired up, just not sure this is very nice but will work for now. diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 955662f3fe..d791295b38 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -18,7 +18,6 @@ namespace Umbraco.Core.Packaging private readonly PackageFileInstallation _packageFileInstallation; private readonly CompiledPackageXmlParser _parser; private readonly IPackageActionRunner _packageActionRunner; - private readonly DirectoryInfo _packageExtractionFolder; private readonly DirectoryInfo _applicationRootFolder; /// @@ -31,11 +30,8 @@ namespace Umbraco.Core.Packaging /// /// The root folder of the application /// - /// - /// The destination root folder to extract the package files (generally the same as applicationRoot) but can be modified for testing - /// public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, - DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) + DirectoryInfo applicationRootFolder) { _packageExtraction = new PackageExtraction(); _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); @@ -43,7 +39,6 @@ namespace Umbraco.Core.Packaging _parser = parser ?? throw new ArgumentNullException(nameof(parser)); _packageActionRunner = packageActionRunner ?? throw new ArgumentNullException(nameof(packageActionRunner)); _applicationRootFolder = applicationRootFolder ?? throw new ArgumentNullException(nameof(applicationRootFolder)); - _packageExtractionFolder = packageExtractionFolder ?? throw new ArgumentNullException(nameof(packageExtractionFolder)); } public CompiledPackage ReadPackage(FileInfo packageFile) @@ -69,7 +64,7 @@ namespace Umbraco.Core.Packaging var packageZipFile = compiledPackage.PackageFile; - var files = _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _packageExtractionFolder.FullName).ToList(); + var files = _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _applicationRootFolder.FullName).ToList(); packageDefinition.Files = files; diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 2b9e50e9e5..4256a66a2d 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -50,8 +50,7 @@ namespace Umbraco.Tests.Packaging PackageDataInstallation, new PackageFileInstallation(Parser, ProfilingLogger), Parser, Mock.Of(), - applicationRootFolder: new DirectoryInfo(IOHelper.GetRootDirectorySafe()), - packageExtractionFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder + applicationRootFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder private const string DocumentTypePickerPackage = "Document_Type_Picker_1.1.umb"; private const string HelloPackage = "Hello_1.0.0.zip"; @@ -106,7 +105,6 @@ namespace Umbraco.Tests.Packaging } [Test] - [Explicit("Will fail on CI?")] public void Can_Read_Compiled_Package_Warnings() { //copy a file to the same path that the package will install so we can detect file conflicts diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 684da2599e..14ffeb743f 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -185,7 +185,6 @@ namespace Umbraco.Tests.TestHelpers new PackageDataInstallation(logger, fileService.Value, macroService.Value, localizationService.Value, dataTypeService.Value, entityService.Value, contentTypeService.Value, contentService.Value, propertyEditorCollection), new PackageFileInstallation(compiledPackageXmlParser, new ProfilingLogger(logger, new TestProfiler())), compiledPackageXmlParser, Mock.Of(), - new DirectoryInfo(IOHelper.GetRootDirectorySafe()), new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); From 355ac09d90f435f96a217c32ce9dbe93852a85bb Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 13:20:19 +1100 Subject: [PATCH 144/223] WIP - moved out the tree and section service from Core, these are web only things, removes their xml parsing, fixes base controller ctor params with UmbracoContext, need to implement tree/section collections taking into account controllers and not scanning so much --- .../Composing/Composers/ServicesComposer.cs | 4 - src/Umbraco.Core/Models/ApplicationTree.cs | 170 ---- src/Umbraco.Core/Models/Section.cs | 22 - src/Umbraco.Core/Services/ISectionService.cs | 114 --- src/Umbraco.Core/Services/ServiceContext.cs | 20 +- src/Umbraco.Core/Umbraco.Core.csproj | 4 - .../Cache/DistributedCacheBinderTests.cs | 7 - .../Packages/Document_Type_Picker_1.1.zip | Bin 0 -> 6147 bytes .../Services/SectionServiceTests.cs | 17 +- .../TestControllerActivatorBase.cs | 3 +- .../TestHelpers/TestObjects-Mocks.cs | 2 - src/Umbraco.Tests/TestHelpers/TestObjects.cs | 6 +- .../TreesAndSections/ApplicationTreeTest.cs | 724 ++++++++--------- .../TreesAndSections/SectionTests.cs | 454 +++++------ .../Cache/ApplicationTreeCacheRefresher.cs | 68 +- .../Cache/DistributedCacheBinder_Handlers.cs | 72 +- .../Cache/DistributedCacheExtensions.cs | 24 +- .../{ => Controllers}/TagsController.cs | 6 +- .../Editors/AuthenticationController.cs | 4 +- .../Editors/BackOfficeServerVariables.cs | 4 +- .../Editors/ContentTypeController.cs | 4 +- .../Editors/ContentTypeControllerBase.cs | 3 +- .../Editors/DashboardController.cs | 4 +- src/Umbraco.Web/Editors/DashboardSecurity.cs | 1 + src/Umbraco.Web/Editors/Dashboards.cs | 1 + src/Umbraco.Web/Editors/EntityController.cs | 16 +- .../Editors/MediaTypeController.cs | 3 +- .../Editors/MemberTypeController.cs | 3 +- .../Editors/PackageInstallController.cs | 4 +- src/Umbraco.Web/Editors/SectionController.cs | 30 +- .../UmbracoAuthorizedJsonController.cs | 4 +- .../Models/ContentEditing/ApplicationTree.cs | 177 +++++ .../ContentEditing/IBackOfficeSection.cs | 15 + .../Models/Mapping/SectionMapperProfile.cs | 3 +- .../Models/Mapping/UserMapperProfile.cs | 1 + .../Models/Trees/ApplicationAttribute.cs | 30 - .../Models/Trees/ApplicationDefinitions.cs | 90 ++- src/Umbraco.Web/Models/Trees/IApplication.cs | 10 - .../Mvc/SurfaceControllerTypeCollection.cs | 2 + .../Runtime/WebRuntimeComponent.cs | 2 + src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 11 + .../Search/SearchableTreeCollection.cs | 1 + .../Services/ApplicationTreeService.cs | 747 +++++++++--------- .../Services/IApplicationTreeService.cs | 121 +-- src/Umbraco.Web/Services/ISectionService.cs | 116 +++ src/Umbraco.Web/Services/SectionService.cs | 443 +++++------ .../Trees/ApplicationTreeController.cs | 33 +- .../Trees/BackOfficeSectionCollection.cs | 21 + src/Umbraco.Web/Trees/TreeCollection.cs | 27 + src/Umbraco.Web/Trees/TreeController.cs | 34 +- src/Umbraco.Web/Trees/TreeControllerBase.cs | 98 +-- ...xtensions.cs => TreeControllerResolver.cs} | 106 ++- .../UI/Pages/UmbracoEnsuredPage.cs | 14 +- src/Umbraco.Web/Umbraco.Web.csproj | 13 +- src/Umbraco.Web/UrlHelperExtensions.cs | 1 - .../Filters/LegacyTreeAuthorizeAttribute.cs | 29 - .../Filters/UmbracoTreeAuthorizeAttribute.cs | 23 +- .../WebApi/UmbracoApiController.cs | 4 +- .../WebApi/UmbracoApiControllerBase.cs | 11 +- .../UmbracoApiControllerTypeCollection.cs | 2 + .../WebApi/UmbracoAuthorizedApiController.cs | 4 +- .../_Legacy/PackageActions/addApplication.cs | 106 +-- 62 files changed, 2043 insertions(+), 2050 deletions(-) delete mode 100644 src/Umbraco.Core/Models/ApplicationTree.cs delete mode 100644 src/Umbraco.Core/Models/Section.cs delete mode 100644 src/Umbraco.Core/Services/ISectionService.cs create mode 100644 src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.zip rename src/Umbraco.Web/{ => Controllers}/TagsController.cs (89%) create mode 100644 src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs create mode 100644 src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs delete mode 100644 src/Umbraco.Web/Models/Trees/ApplicationAttribute.cs delete mode 100644 src/Umbraco.Web/Models/Trees/IApplication.cs rename src/{Umbraco.Core => Umbraco.Web}/Services/IApplicationTreeService.cs (52%) create mode 100644 src/Umbraco.Web/Services/ISectionService.cs create mode 100644 src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs create mode 100644 src/Umbraco.Web/Trees/TreeCollection.cs rename src/Umbraco.Web/Trees/{ApplicationTreeExtensions.cs => TreeControllerResolver.cs} (56%) delete mode 100644 src/Umbraco.Web/WebApi/Filters/LegacyTreeAuthorizeAttribute.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 8c9ccd1088..0b83373d99 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -73,10 +73,6 @@ namespace Umbraco.Core.Composing.Composers factory.GetInstance(), factory.GetInstance(), new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); - //TODO: These are replaced in the web project - we need to declare them so that - // something is wired up, just not sure this is very nice but will work for now. - composition.RegisterUnique(); - composition.RegisterUnique(); return composition; } diff --git a/src/Umbraco.Core/Models/ApplicationTree.cs b/src/Umbraco.Core/Models/ApplicationTree.cs deleted file mode 100644 index ccdebea724..0000000000 --- a/src/Umbraco.Core/Models/ApplicationTree.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using Umbraco.Core.Services; - -namespace Umbraco.Core.Models -{ - [DebuggerDisplay("Tree - {Title} ({ApplicationAlias})")] - public class ApplicationTree - { - private static readonly ConcurrentDictionary ResolvedTypes = new ConcurrentDictionary(); - - /// - /// Initializes a new instance of the class. - /// - public ApplicationTree() { } - - /// - /// Initializes a new instance of the class. - /// - /// if set to true [initialize]. - /// The sort order. - /// The application alias. - /// The tree alias. - /// The tree title. - /// The icon closed. - /// The icon opened. - /// The tree type. - public ApplicationTree(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) - { - Initialize = initialize; - SortOrder = sortOrder; - ApplicationAlias = applicationAlias; - Alias = alias; - Title = title; - IconClosed = iconClosed; - IconOpened = iconOpened; - Type = type; - - } - - /// - /// Gets or sets a value indicating whether this should initialize. - /// - /// true if initialize; otherwise, false. - public bool Initialize { get; set; } - - /// - /// Gets or sets the sort order. - /// - /// The sort order. - public int SortOrder { get; set; } - - /// - /// Gets the application alias. - /// - /// The application alias. - public string ApplicationAlias { get; } - - /// - /// Gets the tree alias. - /// - /// The alias. - public string Alias { get; } - - /// - /// Gets or sets the tree title. - /// - /// The title. - public string Title { get; set; } - - /// - /// Gets or sets the icon closed. - /// - /// The icon closed. - public string IconClosed { get; set; } - - /// - /// Gets or sets the icon opened. - /// - /// The icon opened. - public string IconOpened { get; set; } - - /// - /// Gets or sets the tree type assembly name. - /// - /// The type. - public string Type { get; set; } - - /// - /// Returns the localized root node display name - /// - /// - /// - public string GetRootNodeDisplayName(ILocalizedTextService textService) - { - var label = $"[{Alias}]"; - - // try to look up a the localized tree header matching the tree alias - var localizedLabel = textService.Localize("treeHeaders/" + Alias); - - // if the localizedLabel returns [alias] then return the title attribute from the trees.config file, if it's defined - if (localizedLabel != null && localizedLabel.Equals(label, StringComparison.InvariantCultureIgnoreCase)) - { - if (string.IsNullOrEmpty(Title) == false) - label = Title; - } - else - { - // the localizedLabel translated into something that's not just [alias], so use the translation - label = localizedLabel; - } - - return label; - } - - private Type _runtimeType; - - /// - /// Returns the CLR type based on it's assembly name stored in the config - /// - /// - public Type GetRuntimeType() - { - return _runtimeType ?? (_runtimeType = System.Type.GetType(Type)); - } - - /// - /// Used to try to get and cache the tree type - /// - /// - /// - internal static Type TryGetType(string type) - { - try - { - return ResolvedTypes.GetOrAdd(type, s => - { - var result = System.Type.GetType(type); - if (result != null) - { - return result; - } - - //we need to implement a bit of a hack here due to some trees being renamed and backwards compat - var parts = type.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - if (parts.Length != 2) - throw new InvalidOperationException("Could not resolve type"); - if (parts[1].Trim() != "Umbraco.Web" || parts[0].StartsWith("Umbraco.Web.Trees") == false || parts[0].EndsWith("Controller")) - throw new InvalidOperationException("Could not resolve type"); - - //if it's one of our controllers but it's not suffixed with "Controller" then add it and try again - var tempType = parts[0] + "Controller, Umbraco.Web"; - - result = System.Type.GetType(tempType); - if (result != null) - return result; - - throw new InvalidOperationException("Could not resolve type"); - }); - } - catch (InvalidOperationException) - { - //swallow, this is our own exception, couldn't find the type - // fixme bad use of exceptions here! - return null; - } - } - } -} diff --git a/src/Umbraco.Core/Models/Section.cs b/src/Umbraco.Core/Models/Section.cs deleted file mode 100644 index 4b7f8309dd..0000000000 --- a/src/Umbraco.Core/Models/Section.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Umbraco.Core.Models -{ - /// - /// Represents a section defined in the app.config file. - /// - public class Section - { - public Section(string name, string @alias, int sortOrder) - { - Name = name; - Alias = alias; - SortOrder = sortOrder; - } - - public Section() - { } - - public string Name { get; set; } - public string Alias { get; set; } - public int SortOrder { get; set; } - } -} diff --git a/src/Umbraco.Core/Services/ISectionService.cs b/src/Umbraco.Core/Services/ISectionService.cs deleted file mode 100644 index 899ae78245..0000000000 --- a/src/Umbraco.Core/Services/ISectionService.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System.Collections.Generic; -using Umbraco.Core.Models; - -namespace Umbraco.Core.Services -{ - public interface ISectionService - { - /// - /// The cache storage for all applications - /// - IEnumerable
GetSections(); - - /// - /// Get the user group's allowed sections - /// - /// - /// - IEnumerable
GetAllowedSections(int userId); - - /// - /// Gets the application by its alias. - /// - /// The application alias. - /// - Section GetByAlias(string appAlias); - - /// - /// Creates a new applcation if no application with the specified alias is found. - /// - /// The application name. - /// The application alias. - /// The application icon, which has to be located in umbraco/images/tray folder. - void MakeNew(string name, string alias, string icon); - - /// - /// Makes the new. - /// - /// The name. - /// The alias. - /// The icon. - /// The sort order. - void MakeNew(string name, string alias, string icon, int sortOrder); - - /// - /// Deletes the section - /// - void DeleteSection(Section section); - } - - /// - /// Purely used to allow a service context to create the default services - /// - internal class EmptySectionService : ISectionService - { - /// - /// The cache storage for all applications - /// - public IEnumerable
GetSections() - { - throw new System.NotImplementedException(); - } - - /// - /// Get the user's allowed sections - /// - /// - /// - public IEnumerable
GetAllowedSections(int userId) - { - throw new System.NotImplementedException(); - } - - /// - /// Gets the application by its alias. - /// - /// The application alias. - /// - public Section GetByAlias(string appAlias) - { - throw new System.NotImplementedException(); - } - - /// - /// Creates a new applcation if no application with the specified alias is found. - /// - /// The application name. - /// The application alias. - /// The application icon, which has to be located in umbraco/images/tray folder. - public void MakeNew(string name, string alias, string icon) - { - throw new System.NotImplementedException(); - } - - /// - /// Makes the new. - /// - /// The name. - /// The alias. - /// The icon. - /// The sort order. - public void MakeNew(string name, string alias, string icon, int sortOrder) - { - throw new System.NotImplementedException(); - } - - /// - /// Deletes the section - /// - public void DeleteSection(Section section) - { - throw new System.NotImplementedException(); - } - } -} diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index 731d3a58c6..6d7ac8a5e7 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -25,8 +25,6 @@ namespace Umbraco.Core.Services private readonly Lazy _serverRegistrationService; private readonly Lazy _entityService; private readonly Lazy _relationService; - private readonly Lazy _treeService; - private readonly Lazy _sectionService; private readonly Lazy _macroService; private readonly Lazy _memberTypeService; private readonly Lazy _memberGroupService; @@ -38,7 +36,7 @@ namespace Umbraco.Core.Services /// /// Initializes a new instance of the class with lazy services. /// - public ServiceContext(Lazy publicAccessService, Lazy domainService, Lazy auditService, Lazy localizedTextService, Lazy tagService, Lazy contentService, Lazy userService, Lazy memberService, Lazy mediaService, Lazy contentTypeService, Lazy mediaTypeService, Lazy dataTypeService, Lazy fileService, Lazy localizationService, Lazy packagingService, Lazy serverRegistrationService, Lazy entityService, Lazy relationService, Lazy treeService, Lazy sectionService, Lazy macroService, Lazy memberTypeService, Lazy memberGroupService, Lazy notificationService, Lazy externalLoginService, Lazy redirectUrlService, Lazy consentService) + public ServiceContext(Lazy publicAccessService, Lazy domainService, Lazy auditService, Lazy localizedTextService, Lazy tagService, Lazy contentService, Lazy userService, Lazy memberService, Lazy mediaService, Lazy contentTypeService, Lazy mediaTypeService, Lazy dataTypeService, Lazy fileService, Lazy localizationService, Lazy packagingService, Lazy serverRegistrationService, Lazy entityService, Lazy relationService, Lazy macroService, Lazy memberTypeService, Lazy memberGroupService, Lazy notificationService, Lazy externalLoginService, Lazy redirectUrlService, Lazy consentService) { _publicAccessService = publicAccessService; _domainService = domainService; @@ -58,8 +56,6 @@ namespace Umbraco.Core.Services _serverRegistrationService = serverRegistrationService; _entityService = entityService; _relationService = relationService; - _treeService = treeService; - _sectionService = sectionService; _macroService = macroService; _memberTypeService = memberTypeService; _memberGroupService = memberGroupService; @@ -90,8 +86,6 @@ namespace Umbraco.Core.Services IMemberTypeService memberTypeService = null, IMemberService memberService = null, IUserService userService = null, - ISectionService sectionService = null, - IApplicationTreeService treeService = null, ITagService tagService = null, INotificationService notificationService = null, ILocalizedTextService localizedTextService = null, @@ -125,8 +119,6 @@ namespace Umbraco.Core.Services Lazy(serverRegistrationService), Lazy(entityService), Lazy(relationService), - Lazy(treeService), - Lazy(sectionService), Lazy(macroService), Lazy(memberTypeService), Lazy(memberGroupService), @@ -236,16 +228,6 @@ namespace Umbraco.Core.Services ///
public IMemberService MemberService => _memberService.Value; - /// - /// Gets the - /// - public ISectionService SectionService => _sectionService.Value; - - /// - /// Gets the - /// - public IApplicationTreeService ApplicationTreeService => _treeService.Value; - /// /// Gets the MemberTypeService /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 2236854351..8395dd9cb8 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -678,7 +678,6 @@ - @@ -875,7 +874,6 @@ - @@ -1390,7 +1388,6 @@ - @@ -1420,7 +1417,6 @@ - diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index 50b27da89f..3532a11c63 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -47,13 +47,6 @@ namespace Umbraco.Tests.Cache //Permission.Deleted += PermissionDeleted; //PermissionRepository.AssignedPermissions += CacheRefresherEventHandler_AssignedPermissions; - new EventDefinition(null, serviceContext.ApplicationTreeService, new EventArgs(), "Deleted"), - new EventDefinition(null, serviceContext.ApplicationTreeService, new EventArgs(), "Updated"), - new EventDefinition(null, serviceContext.ApplicationTreeService, new EventArgs(), "New"), - - new EventDefinition(null, serviceContext.SectionService, new EventArgs(), "Deleted"), - new EventDefinition(null, serviceContext.SectionService, new EventArgs(), "New"), - new EventDefinition>(null, serviceContext.UserService, new SaveEventArgs(Enumerable.Empty())), new EventDefinition>(null, serviceContext.UserService, new DeleteEventArgs(Enumerable.Empty())), new EventDefinition>(null, serviceContext.UserService, new SaveEventArgs(Enumerable.Empty())), diff --git a/src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.zip b/src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..18449bd3735870c98e711525a7ea9883941e321f GIT binary patch literal 6147 zcma)=RZJWVl!bAp6qn)@DHL~ich`a9GDv|U9o*dqXP~$j8>HwIcc+6CcZxg3_Ww7V z%_f^o_TGmt_vYr@m-BSARFP4L5D*YB5dOwu%SOrHjmG{vav>nF{0m`zTP^`UD|RbO zJ{xvEJ{}u(VJ6 z>RqIdc64-an*}K5AZ-UAemx4uIqk2~WIP~j*f$8$!If+UInR2e$q(g!=FuH-F4L-4 z9dYM91Y;{#CsPV><>WPb+O>B}bWg&$d6f8SWagJ$DRHjNnOwXeRSe4r{pSursKP2+ z5*!Csj==m?xdmqNt(gZb?I}|u@T-17dXyRCfw)Zm+V*Ay#4LOW7g^5bn$2t^_RxbI zb~nFqnEJIPe82VAW1vgLGN5?NciA2C@u8*RO#64`l1El`KGb^eq{hBl4d;)_RN9|h z;2vSvnrG6N7_BRX3JZ;r19(S{2)`5E;kr~#Mr_~Kl~nJtaO8z|tn0FriIPLEk-0X6 zvkrodN)M#{Ib62%^qF1q_<~==kbKIOK6YgSp`>(Lk|N2qo8u_hSPg*eGz2WtsELJg z&i!U|fb7dz**KzB*2#Yx-xvl~W{KI5olssKlTbSoK4HwQbkz%LRT0Zs&^mDvdZM^f zaJ6-Hs!Z$PJ3v>ei2UT60fWv}du)Y_hI){-2L5Ct%oxT=k6UZvoJj>&I^!)jbKH&Z zn`AY%?Dat5!Xs-{1DBUi;|eN+y0ooBU9<+W zXtE^aR5vrFAIN4;N9Ijz8F;tVH*fW17b6FKG25!*j&7OkS`7Kf{_6PgnqvHT(@?hk zLv`$3uPtrWhuOD|xBV3K-Z=x^L*J84#xI&3h8UoEF81qz>!y#mJLY5D1@>wIkH3r( zKD4hMlFtyiV)%T#VfSo7!H3Sox<$um(_bE!wiwmw%hWWmIl0OA#aZY==|=ILqn824 zdZOgHV!5W3XWn)GHS;s9Br+0=)89}`$X;b0zt|G{kaO!YVoO;^U|9U?4*?C z!%|*r>zZj^}+;2PT53CIGVe$h&mj**Cis2A- z`8%{XPB83WbizI%%r;n-d1*hl?rK}yc6^H~msEv1`WhYfE;4vHO~yK60KQbPy+H~& z`rp(kJ4~kAZ*nz~nKy2r#MMU^21S{qW`tix;>?ZXUT`dLZ6bRY-q$g#o^Br|Ldz)_ zDg*O{d2CY7!@cjB=Op+FYx~N>fq<(Ap`nroe+W26+&nUTGK}0iDtO^=(%MYj)iRO# z?oT?0ZWTHZ_P``(^9-`JtTQyLdIA#NI|)c0!3Dc?);nWKZ{Cszq-_5F9y*io>5Hs_ zAnWq_~2s-hqXHNdHM>xV6h`*qRK!=$MrB=hXz+vHdBI$$LU=ggLL z^jO=a$aVtKjpt#M5lUhlQ9Qx@QXkS}vB$}6U~xu4-=rlJC}joEaE7=&(6 z-FR1gL)Z7leecjH^`_wsAd@Ib5u$uuuP82a*C4daRl_d$88oY z?qOz0+t3y^;Qp(6uXXmoj0;jop*I%skt<_q-YP(blUACHztsDilz|0Jd@ULU$sc+RLK@h*@r?;B}v z5IR{Rml=D#;)V+nRmdHtzuv~~FmDRVv)(rn+fk1Yzhcp14yw3Di#tW^85Hq1ZQVh1EGVb^Pax`C0-tS*wo!YH)*C?b4l>Vd)h$bQvM zNSz2P#E`kRXV;MRxn)F7ARMWiXcSQ(iu@Eq6X`bGc#i~zADH>Am4e1_OzOkKBI!m< z5joA{8()ep_|OZrSOWD$LqRZUQF*|}qFR(&V0a?+IQvVvdeiP8IhwTVglv`-h2`=uZ zwI0SrzXM<)cRy#(T3;a9U#glApBlWuG3yBb(Dk~5p$5_3H;wnI@2XOw=YrfS{!*7u z!a)pbk#MBP%1@F8K3KPxe-~fzp(YrDTIB`9&np ztMlJ}{Q*|$yDUgbRY&CGkDxUh_5?3`NWEGwS7;n+Y6(spup!c*h{@AP*SUfef@0ej zlCCAABKL2mkX~}vCOp`U((16TP~2 zxKU*Dd2$2VNmPQMwt~1_3Aj|k8m7@uWe7mq1%nXTy!oGrE^CkEty^Pbnro5D>Aspl ziUt=k7gWZqNu}1Qa&_*oo?Z2$e^eRLTjSg3$omYe6;Z8!i9pU+Of8oM{Iqvl_}wkRr_ix0&v0i6~@8!2pJC z0?yO1Lt}PzprseZS^620EvXAmX#;6|$gCV5aw66pHHh;7pohN53HJUgym11h0jGT- znJ#Tb$S;1B9Xh0Q7{kcJ_icsw*?<*Go{dAqDRdLD{m}#B1gZm$H28~O^a20@7UFd; z^36^G%h6?Y1+qrj_`+%8r5B+Oov?kBJsBZ})OR8HZny>6jN6V{zL7h7RpcaO z5gO`zz>0is7z+KjO(6iDFK#}CfU5I7l!)6=*Ub>G`aIq+tQvmPydGtaCD@oHL7j90pUrRf%j^&T{Jpd~)}G*FsWLG6xG|$2-QLDh zs_|#`jtveNrTh3?w*S(#Uy?=#qbF-XKV_X`86NIM@j3^XQuIuxS==-_^47lWv$vJq zAS-P47_7Qm>CT+iJm*k8G{$l8J-3y)##sctTD3kLG_*=!qr&g1_QQB(#59Eb%crLV zyB0Zy2en_nt@k~(T!~f6Jdu38;wfg|vSD{Jz{iU_vPH+URQobavCM`S`ojBP9;v#WL= z>Z>yLbwtLvJL$L%%hHAtZ)_WxxdjDH?IaWh#|7-DgT4f|^*0Mk?5N0h@9(^Ql#GIQ zIPZo_?1=li8lhhfl>D5VUi_o>5u6|BkcdlML!dv$Kug0CZ>N#VXU~Vj14NKiemoKL z8^EUPT9E^p7+)OUXJn4d@ETz@+s$N&yHVJsIlvm?kZ-d?&o2WH?C?`O%u(#MA9=o$ zFRG_EyMLUP8e&~#83rVlo?X{NHswSt)xi)PQDuT0WK_FkPNI*INOd%XY!yZvU(ZCP zliy@uGXh7|XauM@$j8aYgvj>o&U@JHj=HIZDP;bHTs~l z#J%r#h;A3H8V{i4hs=?{$rrsAJ!&sZf`nK1fw!_E1@2Ahg8SUhmgqI(azDLQ4M@iN zC^^OE24Bns*a5 zYX13M#}>VKWJ{)NbfNLRWwol7POHxS-zz(`+@#DH?~BEaN{`5>vKM7uzs4yEHtZ6? z%b<$VnhJ`OpC?)Tqq&=9t&ST?%NVFxmMrV7#gut+RWr>z947bo(U#Wsuepn;P z2CFR7mLNf@aY{4MQuz%Ey_;>92&Gazd0)1pkuV>KwP$FYH0)fzzAyzRb18KS!#fP| zDm)@sn%t?!zS76PA{H;7zsbm`LvQ< zujr5-h3qLt)ms{ZJ(|eq>yHUna6T$~q`<+!`i{I(0_}hdrjfw{)sLA>FU8Y#MTJzp z*e50C?c_m#FH~OBZ=h(72(>P=r?NoiPd(G^7sqAn!C@OdA#19pGdl0kztLc)mT@T{ z7Be~GoNdd0Ql|LXVMXGm$s{cIE-K^)y>^vSo|GH9rXpxxY-9~l>K#GNBhG=cQF4E7 zPQ)#W|4u#$G>eS?!x}d`c5DPSs!rJR`EPK;qm=L;;3B%{6}`SczsYyVAJc^r&E~K3qG|;RjqSU&+G3p*#4?VcqDZL6ezyGN!?Y&PAwMCGXttI%{xhL8yTaq?Eq< z!Dq0=I+ttmY;wh-`*-ieub$qXlxxTIW~q$@is3z}pp}|?M^7ZTK{O0Ozv+k!XItJ+ ztD2PAu@d&U|2j?_Wf89v($Jg`iub|tXMYh$t*YDIY6l0NCw1QrW4HSAJsemBZ5|$j zc=CN$8#*Yuse0CY|4tT1nYIGD4da+(W(J81-!t|qml8NsXvJnZY`DH*u52LwX6eOO zS=lmpgRjK@9j`nq4@p?zC}%LCs(}HYF7g11dgq<8GP&Ae+?Lx6RC8wWoWnR|#or^n z#*ni+O-L?dB$%ySp}o{={FHmXPRfKTAdMzNu`Kd!M#z({447Y!hR=?#UPT;3TsRPy zp4Ci{VaAufHd_@(ddu4eCH3r1WMq6r})JmSFPFdJrM`@a{?6axWC`G}A^DqGoIlg>9x%ssmFHAc zA;yh4FL&ObY{WN%1-N@ZkQEL$$G;3WwzQ5C?2izkG6-CG9J)TO|IP@-u!NrV(IF!O z^B$y&*w-qd>0l#76lq7<_+~i>wK9}j-kQ0>a__4_Y*flT4t|0TMxo|Gdl@&YMrW|_ zyf>Rk#+sy%!PnQtW14igo!1F%z6^)&_4m-!DYYxrb*s~~n$M{#zt~jJ>Kv8V(9+i4 z*g{(07N zU#$Pmp^gUD6>_j~06U-(Tzh@KF1lDf`}$<|G`?Nw)~I&+x44+O+%wT@SuA!g(T~rN zmHKA#w_@Giy|&*|g5qw%ZWaBZm22Khof#gU!Ab#UAiM>3)4w63*ZCrZ{O}|}InXr) zDEm-=^Z;@c|HA%q!+sU`IP!MD@9;zfov$>&X%zS7{fYQ{R}k>5k%iHQbAPk6 zv>`9*-r5WeOnzihj!z!MY(Xwx=F_No(zlR6)h*&N*Y?j*K;h+iW6?!6m(t{sdS4>4 zTY#&rxiRB(jqCp|IZW2TpJOt1#LY=mIgpIsnu_FWt6e;Mw;{xXkgAk8nI`qZsD(Bv zyvkm`XZB0;m2<6&qi_R=jZU%pn;+RV=FBo@`K9B9KhnO?%gL_4Nh)<;z>P1{#oja~ zP5Tq~;tO(M&{(VFdC$4z)(}~%)j} zHaDuLH34?Tfy}eJl|Mlb3)|1$JHVBocd@TYa85+6|IRZ*9m?fCGU0)xkq{6-Cf*ZaN#F@~PP8t@EI#8X^FN|lf;z-*2tigPkH zbrg##Zrs60*X2O={)MXU%7Jr7nG#W4#aq<9*%R6EOj#p%)rC#(AeEk5y&=)qjcZUYRKJY3dvzFX0C%hZGvfmP~T#f zQE#0|`ZS;WNqe8?#T>YB${6@t4y*v{!=MN#$xTUjBy>z@K=aez!CKP*$1RsptqQGc zk|dGUV%496zS~E$+R}9%)*?sIBLm?z(d9%m`4Vn|Q4@2fa3w3t2p9ictT=2AdNUk? zLMN+KIpxkKthpLGVjEiap8)2v_dljd3GU)?Wp^bc@nX?%6L_7;3XYi#EDg^QzNTP` zBCVgG%9kK`2UACUoY-(lhqhT1bsm4*L4MLduukZszN-JxqW4DwVYV}pKLAJ%KHlO7 zpyewOysjBD1=o3I%T2PT-pko?rE%RcxC@rsV8_gkw$Oz4V4M&15?no@=0_tjhZ+fC z8$IL`v60`W-u5o)k=v(nZlh|cA|eqX{NLI6KX&^c_5V%M|5cUzFV+9;;P?NfNc#_` z|9SmC{EUV0?-Bt45rGV0H$DE%j^h-f<+aM~_CI_MRr*hAsiLC&dxP{(H~m8q(toG_ E0K6^9ApigX literal 0 HcmV?d00001 diff --git a/src/Umbraco.Tests/Services/SectionServiceTests.cs b/src/Umbraco.Tests/Services/SectionServiceTests.cs index ca5d755220..206c99ffbf 100644 --- a/src/Umbraco.Tests/Services/SectionServiceTests.cs +++ b/src/Umbraco.Tests/Services/SectionServiceTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using Umbraco.Core.Models.Membership; using Umbraco.Tests.Testing; +using Umbraco.Web.Services; namespace Umbraco.Tests.Services { @@ -14,24 +15,20 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] public class SectionServiceTests : TestWithSomeContentBase { - public override void CreateTestData() - { - base.CreateTestData(); - - ServiceContext.SectionService.MakeNew("Content", "content", "icon-content"); - ServiceContext.SectionService.MakeNew("Media", "media", "icon-media"); - ServiceContext.SectionService.MakeNew("Settings", "settings", "icon-settings"); - ServiceContext.SectionService.MakeNew("Developer", "developer", "icon-developer"); - } + //fixme + private ISectionService SectionService => new SectionService(ServiceContext.UserService, null, null); + [Test] public void SectionService_Can_Get_Allowed_Sections_For_User() { + //fixme - need to mock + // Arrange var user = CreateTestUser(); // Act - var result = ServiceContext.SectionService.GetAllowedSections(user.Id).ToList(); + var result = SectionService.GetAllowedSections(user.Id).ToList(); // Assert Assert.AreEqual(3, result.Count); diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 9e2a2156ee..31ee34843d 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -60,8 +60,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting memberTypeService: mockedMemberTypeService, dataTypeService: mockedDataTypeService, contentTypeService: mockedContentTypeService, - localizedTextService:Mock.Of(), - sectionService:Mock.Of()); + localizedTextService:Mock.Of()); var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 8c230f98d0..4dfaa9e674 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -73,8 +73,6 @@ namespace Umbraco.Tests.TestHelpers MockService(container), MockService(container), MockService(container), - MockService(container), - MockService(container), MockService(container), MockService(container), MockService(container), diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 14ffeb743f..f7f0d26c0e 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -188,9 +188,7 @@ namespace Umbraco.Tests.TestHelpers new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); - var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); - var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var sectionService = GetLazyService(factory, c => new SectionService(userService.Value, treeService.Value, scopeProvider, cache)); + var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var redirectUrlService = GetLazyService(factory, c => new RedirectUrlService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var consentService = GetLazyService(factory, c => new ConsentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); @@ -213,8 +211,6 @@ namespace Umbraco.Tests.TestHelpers serverRegistrationService, entityService, relationService, - treeService, - sectionService, macroService, memberTypeService, memberGroupService, diff --git a/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs b/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs index 951246c535..95d90f1463 100644 --- a/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs +++ b/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs @@ -1,397 +1,397 @@ -using System.IO; -using NUnit.Framework; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using System; -using System.Linq; -using System.Threading; -using Umbraco.Tests.Testing; -using Umbraco.Web.Services; -using Current = Umbraco.Web.Composing.Current; +//using System.IO; +//using NUnit.Framework; +//using Umbraco.Core.Services; +//using Umbraco.Tests.TestHelpers; +//using System; +//using System.Linq; +//using System.Threading; +//using Umbraco.Tests.Testing; +//using Umbraco.Web.Services; +//using Current = Umbraco.Web.Composing.Current; -namespace Umbraco.Tests.TreesAndSections -{ +//namespace Umbraco.Tests.TreesAndSections +//{ - /// - ///This is a test class for ApplicationTreeTest and is intended - ///to contain all ApplicationTreeTest Unit Tests - /// - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ApplicationTreeTest : TestWithDatabaseBase - { - public override void SetUp() - { - base.SetUp(); +// /// +// ///This is a test class for ApplicationTreeTest and is intended +// ///to contain all ApplicationTreeTest Unit Tests +// /// +// [TestFixture] +// [Apartment(ApartmentState.STA)] +// [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] +// public class ApplicationTreeTest : TestWithDatabaseBase +// { +// public override void SetUp() +// { +// base.SetUp(); - var treesConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/trees.config"); - var appConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/applications.config"); - Directory.CreateDirectory(TestHelper.MapPathForTest("~/TEMP/TreesAndSections")); - using (var writer = File.CreateText(treesConfig)) - { - writer.Write(ResourceFiles.trees); - } - using (var writer = File.CreateText(appConfig)) - { - writer.Write(ResourceFiles.applications); - } +// var treesConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/trees.config"); +// var appConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/applications.config"); +// Directory.CreateDirectory(TestHelper.MapPathForTest("~/TEMP/TreesAndSections")); +// using (var writer = File.CreateText(treesConfig)) +// { +// writer.Write(ResourceFiles.trees); +// } +// using (var writer = File.CreateText(appConfig)) +// { +// writer.Write(ResourceFiles.applications); +// } - ApplicationTreeService.TreeConfigFilePath = treesConfig; - SectionService.AppConfigFilePath = appConfig; - } +// //ApplicationTreeService.TreeConfigFilePath = treesConfig; +// SectionService.AppConfigFilePath = appConfig; +// } - public override void TearDown() - { - base.TearDown(); +// public override void TearDown() +// { +// base.TearDown(); - if (Directory.Exists(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"))) - { - Directory.Delete(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"), true); - } - ApplicationTreeService.TreeConfigFilePath = null; - SectionService.AppConfigFilePath = null; - } +// if (Directory.Exists(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"))) +// { +// Directory.Delete(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"), true); +// } +// //ApplicationTreeService.TreeConfigFilePath = null; +// SectionService.AppConfigFilePath = null; +// } - /// - /// Creates a new app tree linked to an application, then delete the application and make sure the tree is gone as well - /// - [Test()] - public void ApplicationTree_Make_New_Then_Delete_App() - { - //create new app - var appName = Guid.NewGuid().ToString("N"); - var treeName = Guid.NewGuid().ToString("N"); - Current.Services.SectionService.MakeNew(appName, appName, "icon.jpg"); +// ///// +// ///// Creates a new app tree linked to an application, then delete the application and make sure the tree is gone as well +// ///// +// //[Test()] +// //public void ApplicationTree_Make_New_Then_Delete_App() +// //{ +// // //create new app +// // var appName = Guid.NewGuid().ToString("N"); +// // var treeName = Guid.NewGuid().ToString("N"); +// // Current.Services.SectionService.MakeNew(appName, appName, "icon.jpg"); - //check if it exists - var app = Current.Services.SectionService.GetByAlias(appName); - Assert.IsNotNull(app); +// // //check if it exists +// // var app = Current.Services.SectionService.GetByAlias(appName); +// // Assert.IsNotNull(app); - //create the new app tree assigned to the new app - Current.Services.ApplicationTreeService.MakeNew(false, 0, app.Alias, treeName, treeName, "icon.jpg", "icon.jpg", "Umbraco.Web.Trees.ContentTreeController, Umbraco.Web"); - var tree = Current.Services.ApplicationTreeService.GetByAlias(treeName); - Assert.IsNotNull(tree); +// // //create the new app tree assigned to the new app +// // Current.Services.ApplicationTreeService.MakeNew(false, 0, app.Alias, treeName, treeName, "icon.jpg", "icon.jpg", "Umbraco.Web.Trees.ContentTreeController, Umbraco.Web"); +// // var tree = Current.Services.ApplicationTreeService.GetByAlias(treeName); +// // Assert.IsNotNull(tree); - //now delete the app - Current.Services.SectionService.DeleteSection(app); +// // //now delete the app +// // Current.Services.SectionService.DeleteSection(app); - //check that the tree is gone - Assert.AreEqual(0, Current.Services.ApplicationTreeService.GetApplicationTrees(treeName).Count()); - } +// // //check that the tree is gone +// // Assert.AreEqual(0, Current.Services.ApplicationTreeService.GetApplicationTrees(treeName).Count()); +// //} - #region Tests to write - ///// - /////A test for ApplicationTree Constructor - ///// - //[TestMethod()] - //public void ApplicationTreeConstructorTest() - //{ - // bool silent = false; // TODO: Initialize to an appropriate value - // bool initialize = false; // TODO: Initialize to an appropriate value - // byte sortOrder = 0; // TODO: Initialize to an appropriate value - // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value - // string alias = string.Empty; // TODO: Initialize to an appropriate value - // string title = string.Empty; // TODO: Initialize to an appropriate value - // string iconClosed = string.Empty; // TODO: Initialize to an appropriate value - // string iconOpened = string.Empty; // TODO: Initialize to an appropriate value - // string assemblyName = string.Empty; // TODO: Initialize to an appropriate value - // string type = string.Empty; // TODO: Initialize to an appropriate value - // string action = string.Empty; // TODO: Initialize to an appropriate value - // ApplicationTree target = new ApplicationTree(silent, initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, assemblyName, type, action); - // Assert.Inconclusive("TODO: Implement code to verify target"); - //} +// #region Tests to write +// ///// +// /////A test for ApplicationTree Constructor +// ///// +// //[TestMethod()] +// //public void ApplicationTreeConstructorTest() +// //{ +// // bool silent = false; // TODO: Initialize to an appropriate value +// // bool initialize = false; // TODO: Initialize to an appropriate value +// // byte sortOrder = 0; // TODO: Initialize to an appropriate value +// // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value +// // string alias = string.Empty; // TODO: Initialize to an appropriate value +// // string title = string.Empty; // TODO: Initialize to an appropriate value +// // string iconClosed = string.Empty; // TODO: Initialize to an appropriate value +// // string iconOpened = string.Empty; // TODO: Initialize to an appropriate value +// // string assemblyName = string.Empty; // TODO: Initialize to an appropriate value +// // string type = string.Empty; // TODO: Initialize to an appropriate value +// // string action = string.Empty; // TODO: Initialize to an appropriate value +// // ApplicationTree target = new ApplicationTree(silent, initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, assemblyName, type, action); +// // Assert.Inconclusive("TODO: Implement code to verify target"); +// //} - ///// - /////A test for ApplicationTree Constructor - ///// - //[TestMethod()] - //public void ApplicationTreeConstructorTest1() - //{ - // ApplicationTree target = new ApplicationTree(); - // Assert.Inconclusive("TODO: Implement code to verify target"); - //} +// ///// +// /////A test for ApplicationTree Constructor +// ///// +// //[TestMethod()] +// //public void ApplicationTreeConstructorTest1() +// //{ +// // ApplicationTree target = new ApplicationTree(); +// // Assert.Inconclusive("TODO: Implement code to verify target"); +// //} - ///// - /////A test for Delete - ///// - //[TestMethod()] - //public void DeleteTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // target.Delete(); - // Assert.Inconclusive("A method that does not return a value cannot be verified."); - //} +// ///// +// /////A test for Delete +// ///// +// //[TestMethod()] +// //public void DeleteTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // target.Delete(); +// // Assert.Inconclusive("A method that does not return a value cannot be verified."); +// //} - ///// - /////A test for Save - ///// - //[TestMethod()] - //public void SaveTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // target.Save(); - // Assert.Inconclusive("A method that does not return a value cannot be verified."); - //} +// ///// +// /////A test for Save +// ///// +// //[TestMethod()] +// //public void SaveTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // target.Save(); +// // Assert.Inconclusive("A method that does not return a value cannot be verified."); +// //} - ///// - /////A test for getAll - ///// - //[TestMethod()] - //public void getAllTest() - //{ - // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value - // ApplicationTree[] actual; - // actual = ApplicationTree.getAll(); - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for getAll +// ///// +// //[TestMethod()] +// //public void getAllTest() +// //{ +// // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value +// // ApplicationTree[] actual; +// // actual = ApplicationTree.getAll(); +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for getApplicationTree - ///// - //[TestMethod()] - //public void getApplicationTreeTest() - //{ - // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value - // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value - // ApplicationTree[] actual; - // actual = ApplicationTree.getApplicationTree(applicationAlias); - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for getApplicationTree +// ///// +// //[TestMethod()] +// //public void getApplicationTreeTest() +// //{ +// // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value +// // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value +// // ApplicationTree[] actual; +// // actual = ApplicationTree.getApplicationTree(applicationAlias); +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for getApplicationTree - ///// - //[TestMethod()] - //public void getApplicationTreeTest1() - //{ - // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value - // bool onlyInitializedApplications = false; // TODO: Initialize to an appropriate value - // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value - // ApplicationTree[] actual; - // actual = ApplicationTree.getApplicationTree(applicationAlias, onlyInitializedApplications); - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for getApplicationTree +// ///// +// //[TestMethod()] +// //public void getApplicationTreeTest1() +// //{ +// // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value +// // bool onlyInitializedApplications = false; // TODO: Initialize to an appropriate value +// // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value +// // ApplicationTree[] actual; +// // actual = ApplicationTree.getApplicationTree(applicationAlias, onlyInitializedApplications); +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for getByAlias - ///// - //[TestMethod()] - //public void getByAliasTest() - //{ - // string treeAlias = string.Empty; // TODO: Initialize to an appropriate value - // ApplicationTree expected = null; // TODO: Initialize to an appropriate value - // ApplicationTree actual; - // actual = ApplicationTree.getByAlias(treeAlias); - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for getByAlias +// ///// +// //[TestMethod()] +// //public void getByAliasTest() +// //{ +// // string treeAlias = string.Empty; // TODO: Initialize to an appropriate value +// // ApplicationTree expected = null; // TODO: Initialize to an appropriate value +// // ApplicationTree actual; +// // actual = ApplicationTree.getByAlias(treeAlias); +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for Action - ///// - //[TestMethod()] - //public void ActionTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.Action = expected; - // actual = target.Action; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for Action +// ///// +// //[TestMethod()] +// //public void ActionTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.Action = expected; +// // actual = target.Action; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for Alias - ///// - //[TestMethod()] - //public void AliasTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string actual; - // actual = target.Alias; - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for Alias +// ///// +// //[TestMethod()] +// //public void AliasTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string actual; +// // actual = target.Alias; +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for ApplicationAlias - ///// - //[TestMethod()] - //public void ApplicationAliasTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string actual; - // actual = target.ApplicationAlias; - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for ApplicationAlias +// ///// +// //[TestMethod()] +// //public void ApplicationAliasTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string actual; +// // actual = target.ApplicationAlias; +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for AssemblyName - ///// - //[TestMethod()] - //public void AssemblyNameTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.AssemblyName = expected; - // actual = target.AssemblyName; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for AssemblyName +// ///// +// //[TestMethod()] +// //public void AssemblyNameTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.AssemblyName = expected; +// // actual = target.AssemblyName; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for IconClosed - ///// - //[TestMethod()] - //public void IconClosedTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.IconClosed = expected; - // actual = target.IconClosed; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for IconClosed +// ///// +// //[TestMethod()] +// //public void IconClosedTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.IconClosed = expected; +// // actual = target.IconClosed; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for IconOpened - ///// - //[TestMethod()] - //public void IconOpenedTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.IconOpened = expected; - // actual = target.IconOpened; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for IconOpened +// ///// +// //[TestMethod()] +// //public void IconOpenedTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.IconOpened = expected; +// // actual = target.IconOpened; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for Initialize - ///// - //[TestMethod()] - //public void InitializeTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // bool expected = false; // TODO: Initialize to an appropriate value - // bool actual; - // target.Initialize = expected; - // actual = target.Initialize; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for Initialize +// ///// +// //[TestMethod()] +// //public void InitializeTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // bool expected = false; // TODO: Initialize to an appropriate value +// // bool actual; +// // target.Initialize = expected; +// // actual = target.Initialize; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for Silent - ///// - //[TestMethod()] - //public void SilentTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // bool expected = false; // TODO: Initialize to an appropriate value - // bool actual; - // target.Silent = expected; - // actual = target.Silent; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for Silent +// ///// +// //[TestMethod()] +// //public void SilentTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // bool expected = false; // TODO: Initialize to an appropriate value +// // bool actual; +// // target.Silent = expected; +// // actual = target.Silent; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for SortOrder - ///// - //[TestMethod()] - //public void SortOrderTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // byte expected = 0; // TODO: Initialize to an appropriate value - // byte actual; - // target.SortOrder = expected; - // actual = target.SortOrder; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for SortOrder +// ///// +// //[TestMethod()] +// //public void SortOrderTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // byte expected = 0; // TODO: Initialize to an appropriate value +// // byte actual; +// // target.SortOrder = expected; +// // actual = target.SortOrder; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for SqlHelper - ///// - //[TestMethod()] - //public void SqlHelperTest() - //{ - // ISqlHelper actual; - // actual = ApplicationTree.SqlHelper; - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for SqlHelper +// ///// +// //[TestMethod()] +// //public void SqlHelperTest() +// //{ +// // ISqlHelper actual; +// // actual = ApplicationTree.SqlHelper; +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for Title - ///// - //[TestMethod()] - //public void TitleTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.Title = expected; - // actual = target.Title; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for Title +// ///// +// //[TestMethod()] +// //public void TitleTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.Title = expected; +// // actual = target.Title; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for Type - ///// - //[TestMethod()] - //public void TypeTest() - //{ - // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.Type = expected; - // actual = target.Type; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} - #endregion +// ///// +// /////A test for Type +// ///// +// //[TestMethod()] +// //public void TypeTest() +// //{ +// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.Type = expected; +// // actual = target.Type; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} +// #endregion - #region Additional test attributes - // - //You can use the following additional attributes as you write your tests: - // - //Use ClassInitialize to run code before running the first test in the class - //[ClassInitialize()] - //public static void MyClassInitialize(TestContext testContext) - //{ - //} - // - //Use ClassCleanup to run code after all tests in a class have run - //[ClassCleanup()] - //public static void MyClassCleanup() - //{ - //} - // - //Use TestInitialize to run code before running each test - //[TestInitialize()] - //public void MyTestInitialize() - //{ - //} - // - //Use TestCleanup to run code after each test has run - //[TestCleanup()] - //public void MyTestCleanup() - //{ - //} - // - #endregion - } -} +// #region Additional test attributes +// // +// //You can use the following additional attributes as you write your tests: +// // +// //Use ClassInitialize to run code before running the first test in the class +// //[ClassInitialize()] +// //public static void MyClassInitialize(TestContext testContext) +// //{ +// //} +// // +// //Use ClassCleanup to run code after all tests in a class have run +// //[ClassCleanup()] +// //public static void MyClassCleanup() +// //{ +// //} +// // +// //Use TestInitialize to run code before running each test +// //[TestInitialize()] +// //public void MyTestInitialize() +// //{ +// //} +// // +// //Use TestCleanup to run code after each test has run +// //[TestCleanup()] +// //public void MyTestCleanup() +// //{ +// //} +// // +// #endregion +// } +//} diff --git a/src/Umbraco.Tests/TreesAndSections/SectionTests.cs b/src/Umbraco.Tests/TreesAndSections/SectionTests.cs index 1f4a01fd3d..83de6c4479 100644 --- a/src/Umbraco.Tests/TreesAndSections/SectionTests.cs +++ b/src/Umbraco.Tests/TreesAndSections/SectionTests.cs @@ -1,252 +1,252 @@ -using System.IO; -using NUnit.Framework; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using System; -using Umbraco.Core.Composing; -using Umbraco.Tests.Testing; -using Umbraco.Web.Services; +//using System.IO; +//using NUnit.Framework; +//using Umbraco.Core.Services; +//using Umbraco.Tests.TestHelpers; +//using System; +//using Umbraco.Core.Composing; +//using Umbraco.Tests.Testing; +//using Umbraco.Web.Services; -namespace Umbraco.Tests.TreesAndSections -{ - /// - ///This is a test class for ApplicationTest and is intended - ///to contain all ApplicationTest Unit Tests - /// - [TestFixture] - [UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class SectionTests : TestWithDatabaseBase - { - protected override void Compose() - { - base.Compose(); - Composition.RegisterUnique(); - } +//namespace Umbraco.Tests.TreesAndSections +//{ +// /// +// ///This is a test class for ApplicationTest and is intended +// ///to contain all ApplicationTest Unit Tests +// /// +// [TestFixture] +// [UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] +// public class SectionTests : TestWithDatabaseBase +// { +// protected override void Compose() +// { +// base.Compose(); +// Composition.RegisterUnique(); +// } - public override void SetUp() - { - base.SetUp(); +// public override void SetUp() +// { +// base.SetUp(); - var treesConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/trees.config"); - var appConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/applications.config"); - Directory.CreateDirectory(TestHelper.MapPathForTest("~/TEMP/TreesAndSections")); - using (var writer = File.CreateText(treesConfig)) - { - writer.Write(ResourceFiles.trees); - } - using (var writer = File.CreateText(appConfig)) - { - writer.Write(ResourceFiles.applications); - } +// var treesConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/trees.config"); +// var appConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/applications.config"); +// Directory.CreateDirectory(TestHelper.MapPathForTest("~/TEMP/TreesAndSections")); +// using (var writer = File.CreateText(treesConfig)) +// { +// writer.Write(ResourceFiles.trees); +// } +// using (var writer = File.CreateText(appConfig)) +// { +// writer.Write(ResourceFiles.applications); +// } - ApplicationTreeService.TreeConfigFilePath = treesConfig; - SectionService.AppConfigFilePath = appConfig; - } +// ApplicationTreeService.TreeConfigFilePath = treesConfig; +// SectionService.AppConfigFilePath = appConfig; +// } - public override void TearDown() - { - base.TearDown(); +// public override void TearDown() +// { +// base.TearDown(); - if (Directory.Exists(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"))) - { - Directory.Delete(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"), true); - } - ApplicationTreeService.TreeConfigFilePath = null; - SectionService.AppConfigFilePath = null; - } +// if (Directory.Exists(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"))) +// { +// Directory.Delete(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"), true); +// } +// ApplicationTreeService.TreeConfigFilePath = null; +// SectionService.AppConfigFilePath = null; +// } - /// - /// Create a new application and delete it - /// - [Test()] - public void Application_Make_New() - { - var name = Guid.NewGuid().ToString("N"); - ServiceContext.SectionService.MakeNew(name, name, "icon.jpg"); +// ///// +// ///// Create a new application and delete it +// ///// +// //[Test()] +// //public void Application_Make_New() +// //{ +// // var name = Guid.NewGuid().ToString("N"); +// // ServiceContext.SectionService.MakeNew(name, name, "icon.jpg"); - //check if it exists - var app = ServiceContext.SectionService.GetByAlias(name); - Assert.IsNotNull(app); +// // //check if it exists +// // var app = ServiceContext.SectionService.GetByAlias(name); +// // Assert.IsNotNull(app); - //now remove it - ServiceContext.SectionService.DeleteSection(app); - Assert.IsNull(ServiceContext.SectionService.GetByAlias(name)); - } +// // //now remove it +// // ServiceContext.SectionService.DeleteSection(app); +// // Assert.IsNull(ServiceContext.SectionService.GetByAlias(name)); +// //} - #region Tests to write +// #region Tests to write - ///// - /////A test for Application Constructor - ///// - //[TestMethod()] - //public void ApplicationConstructorTest() - //{ - // string name = string.Empty; // TODO: Initialize to an appropriate value - // string alias = string.Empty; // TODO: Initialize to an appropriate value - // string icon = string.Empty; // TODO: Initialize to an appropriate value - // Application target = new Application(name, alias, icon); - // Assert.Inconclusive("TODO: Implement code to verify target"); - //} +// ///// +// /////A test for Application Constructor +// ///// +// //[TestMethod()] +// //public void ApplicationConstructorTest() +// //{ +// // string name = string.Empty; // TODO: Initialize to an appropriate value +// // string alias = string.Empty; // TODO: Initialize to an appropriate value +// // string icon = string.Empty; // TODO: Initialize to an appropriate value +// // Application target = new Application(name, alias, icon); +// // Assert.Inconclusive("TODO: Implement code to verify target"); +// //} - ///// - /////A test for Application Constructor - ///// - //[TestMethod()] - //public void ApplicationConstructorTest1() - //{ - // Application target = new Application(); - // Assert.Inconclusive("TODO: Implement code to verify target"); - //} +// ///// +// /////A test for Application Constructor +// ///// +// //[TestMethod()] +// //public void ApplicationConstructorTest1() +// //{ +// // Application target = new Application(); +// // Assert.Inconclusive("TODO: Implement code to verify target"); +// //} - ///// - /////A test for Delete - ///// - //[TestMethod()] - //public void DeleteTest() - //{ - // Application target = new Application(); // TODO: Initialize to an appropriate value - // target.Delete(); - // Assert.Inconclusive("A method that does not return a value cannot be verified."); - //} +// ///// +// /////A test for Delete +// ///// +// //[TestMethod()] +// //public void DeleteTest() +// //{ +// // Application target = new Application(); // TODO: Initialize to an appropriate value +// // target.Delete(); +// // Assert.Inconclusive("A method that does not return a value cannot be verified."); +// //} - ///// - /////A test for MakeNew - ///// - //[TestMethod()] - //public void MakeNewTest1() - //{ - // string name = string.Empty; // TODO: Initialize to an appropriate value - // string alias = string.Empty; // TODO: Initialize to an appropriate value - // string icon = string.Empty; // TODO: Initialize to an appropriate value - // Application.MakeNew(name, alias, icon); - // Assert.Inconclusive("A method that does not return a value cannot be verified."); - //} +// ///// +// /////A test for MakeNew +// ///// +// //[TestMethod()] +// //public void MakeNewTest1() +// //{ +// // string name = string.Empty; // TODO: Initialize to an appropriate value +// // string alias = string.Empty; // TODO: Initialize to an appropriate value +// // string icon = string.Empty; // TODO: Initialize to an appropriate value +// // Application.MakeNew(name, alias, icon); +// // Assert.Inconclusive("A method that does not return a value cannot be verified."); +// //} - ///// - /////A test for RegisterIApplications - ///// - //[TestMethod()] - //public void RegisterIApplicationsTest() - //{ - // Application.RegisterIApplications(); - // Assert.Inconclusive("A method that does not return a value cannot be verified."); - //} +// ///// +// /////A test for RegisterIApplications +// ///// +// //[TestMethod()] +// //public void RegisterIApplicationsTest() +// //{ +// // Application.RegisterIApplications(); +// // Assert.Inconclusive("A method that does not return a value cannot be verified."); +// //} - ///// - /////A test for getAll - ///// - //[TestMethod()] - //public void getAllTest() - //{ - // List expected = null; // TODO: Initialize to an appropriate value - // List actual; - // actual = Application.getAll(); - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for getAll +// ///// +// //[TestMethod()] +// //public void getAllTest() +// //{ +// // List expected = null; // TODO: Initialize to an appropriate value +// // List actual; +// // actual = Application.getAll(); +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for getByAlias - ///// - //[TestMethod()] - //public void getByAliasTest() - //{ - // string appAlias = string.Empty; // TODO: Initialize to an appropriate value - // Application expected = null; // TODO: Initialize to an appropriate value - // Application actual; - // actual = Application.getByAlias(appAlias); - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for getByAlias +// ///// +// //[TestMethod()] +// //public void getByAliasTest() +// //{ +// // string appAlias = string.Empty; // TODO: Initialize to an appropriate value +// // Application expected = null; // TODO: Initialize to an appropriate value +// // Application actual; +// // actual = Application.getByAlias(appAlias); +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for SqlHelper - ///// - //[TestMethod()] - //public void SqlHelperTest() - //{ - // ISqlHelper actual; - // actual = Application.SqlHelper; - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for SqlHelper +// ///// +// //[TestMethod()] +// //public void SqlHelperTest() +// //{ +// // ISqlHelper actual; +// // actual = Application.SqlHelper; +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for alias - ///// - //[TestMethod()] - //public void aliasTest() - //{ - // Application target = new Application(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.alias = expected; - // actual = target.alias; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for alias +// ///// +// //[TestMethod()] +// //public void aliasTest() +// //{ +// // Application target = new Application(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.alias = expected; +// // actual = target.alias; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for icon - ///// - //[TestMethod()] - //public void iconTest() - //{ - // Application target = new Application(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.icon = expected; - // actual = target.icon; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} +// ///// +// /////A test for icon +// ///// +// //[TestMethod()] +// //public void iconTest() +// //{ +// // Application target = new Application(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.icon = expected; +// // actual = target.icon; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} - ///// - /////A test for name - ///// - //[TestMethod()] - //public void nameTest() - //{ - // Application target = new Application(); // TODO: Initialize to an appropriate value - // string expected = string.Empty; // TODO: Initialize to an appropriate value - // string actual; - // target.name = expected; - // actual = target.name; - // Assert.AreEqual(expected, actual); - // Assert.Inconclusive("Verify the correctness of this test method."); - //} - #endregion +// ///// +// /////A test for name +// ///// +// //[TestMethod()] +// //public void nameTest() +// //{ +// // Application target = new Application(); // TODO: Initialize to an appropriate value +// // string expected = string.Empty; // TODO: Initialize to an appropriate value +// // string actual; +// // target.name = expected; +// // actual = target.name; +// // Assert.AreEqual(expected, actual); +// // Assert.Inconclusive("Verify the correctness of this test method."); +// //} +// #endregion - #region Additional test attributes - // - //You can use the following additional attributes as you write your tests: - // - //Use ClassInitialize to run code before running the first test in the class - //[ClassInitialize()] - //public static void MyClassInitialize(TestContext testContext) - //{ - //} - // - //Use ClassCleanup to run code after all tests in a class have run - //[ClassCleanup()] - //public static void MyClassCleanup() - //{ - //} - // - //Use TestInitialize to run code before running each test - //[TestInitialize()] - //public void MyTestInitialize() - //{ - //} - // - //Use TestCleanup to run code after each test has run - //[TestCleanup()] - //public void MyTestCleanup() - //{ - //} - // - #endregion - } -} +// #region Additional test attributes +// // +// //You can use the following additional attributes as you write your tests: +// // +// //Use ClassInitialize to run code before running the first test in the class +// //[ClassInitialize()] +// //public static void MyClassInitialize(TestContext testContext) +// //{ +// //} +// // +// //Use ClassCleanup to run code after all tests in a class have run +// //[ClassCleanup()] +// //public static void MyClassCleanup() +// //{ +// //} +// // +// //Use TestInitialize to run code before running each test +// //[TestInitialize()] +// //public void MyTestInitialize() +// //{ +// //} +// // +// //Use TestCleanup to run code after each test has run +// //[TestCleanup()] +// //public void MyTestCleanup() +// //{ +// //} +// // +// #endregion +// } +//} diff --git a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs index 247c33c361..4d6740a0b1 100644 --- a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs @@ -1,46 +1,46 @@ -using System; -using Umbraco.Core.Cache; +//using System; +//using Umbraco.Core.Cache; -namespace Umbraco.Web.Cache -{ - public sealed class ApplicationTreeCacheRefresher : CacheRefresherBase - { - public ApplicationTreeCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) - { } +//namespace Umbraco.Web.Cache +//{ +// public sealed class ApplicationTreeCacheRefresher : CacheRefresherBase +// { +// public ApplicationTreeCacheRefresher(CacheHelper cacheHelper) +// : base(cacheHelper) +// { } - #region Define +// #region Define - protected override ApplicationTreeCacheRefresher This => this; +// protected override ApplicationTreeCacheRefresher This => this; - public static readonly Guid UniqueId = Guid.Parse("0AC6C028-9860-4EA4-958D-14D39F45886E"); +// public static readonly Guid UniqueId = Guid.Parse("0AC6C028-9860-4EA4-958D-14D39F45886E"); - public override Guid RefresherUniqueId => UniqueId; +// public override Guid RefresherUniqueId => UniqueId; - public override string Name => "Application Tree Cache Refresher"; +// public override string Name => "Application Tree Cache Refresher"; - #endregion +// #endregion - #region Refresher +// #region Refresher - public override void RefreshAll() - { - CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); - base.RefreshAll(); - } +// public override void RefreshAll() +// { +// CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); +// base.RefreshAll(); +// } - public override void Refresh(int id) - { - Remove(id); - base.Refresh(id); - } +// public override void Refresh(int id) +// { +// Remove(id); +// base.Refresh(id); +// } - public override void Remove(int id) - { - CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); - base.Remove(id); - } +// public override void Remove(int id) +// { +// CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); +// base.Remove(id); +// } - #endregion - } -} +// #endregion +// } +//} diff --git a/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs b/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs index d522e54de6..421eb546a4 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs @@ -46,19 +46,19 @@ namespace Umbraco.Web.Cache _logger.Info("Initializing Umbraco internal event handlers for cache refreshing."); - // bind to application tree events - Bind(() => ApplicationTreeService.Deleted += ApplicationTreeService_Deleted, - () => ApplicationTreeService.Deleted -= ApplicationTreeService_Deleted); - Bind(() => ApplicationTreeService.Updated += ApplicationTreeService_Updated, - () => ApplicationTreeService.Updated -= ApplicationTreeService_Updated); - Bind(() => ApplicationTreeService.New += ApplicationTreeService_New, - () => ApplicationTreeService.New -= ApplicationTreeService_New); + //// bind to application tree events + //Bind(() => ApplicationTreeService.Deleted += ApplicationTreeService_Deleted, + // () => ApplicationTreeService.Deleted -= ApplicationTreeService_Deleted); + //Bind(() => ApplicationTreeService.Updated += ApplicationTreeService_Updated, + // () => ApplicationTreeService.Updated -= ApplicationTreeService_Updated); + //Bind(() => ApplicationTreeService.New += ApplicationTreeService_New, + // () => ApplicationTreeService.New -= ApplicationTreeService_New); - // bind to application events - Bind(() => SectionService.Deleted += SectionService_Deleted, - () => SectionService.Deleted -= SectionService_Deleted); - Bind(() => SectionService.New += SectionService_New, - () => SectionService.New -= SectionService_New); + //// bind to application events + //Bind(() => SectionService.Deleted += SectionService_Deleted, + // () => SectionService.Deleted -= SectionService_Deleted); + //Bind(() => SectionService.New += SectionService_New, + // () => SectionService.New -= SectionService_New); // bind to user and user group events Bind(() => UserService.SavedUserGroup += UserService_SavedUserGroup, @@ -231,38 +231,38 @@ namespace Umbraco.Web.Cache #endregion - #region ApplicationTreeService + //#region ApplicationTreeService - private void ApplicationTreeService_New(ApplicationTree sender, EventArgs e) - { - _distributedCache.RefreshAllApplicationTreeCache(); - } + //private void ApplicationTreeService_New(ApplicationTree sender, EventArgs e) + //{ + // _distributedCache.RefreshAllApplicationTreeCache(); + //} - private void ApplicationTreeService_Updated(ApplicationTree sender, EventArgs e) - { - _distributedCache.RefreshAllApplicationTreeCache(); - } + //private void ApplicationTreeService_Updated(ApplicationTree sender, EventArgs e) + //{ + // _distributedCache.RefreshAllApplicationTreeCache(); + //} - private void ApplicationTreeService_Deleted(ApplicationTree sender, EventArgs e) - { - _distributedCache.RefreshAllApplicationTreeCache(); - } + //private void ApplicationTreeService_Deleted(ApplicationTree sender, EventArgs e) + //{ + // _distributedCache.RefreshAllApplicationTreeCache(); + //} - #endregion + //#endregion - #region Application event handlers + //#region Application event handlers - private void SectionService_New(ISectionService sender, EventArgs e) - { - _distributedCache.RefreshAllApplicationCache(); - } + //private void SectionService_New(ISectionService sender, EventArgs e) + //{ + // _distributedCache.RefreshAllApplicationCache(); + //} - private void SectionService_Deleted(ISectionService sender, EventArgs e) - { - _distributedCache.RefreshAllApplicationCache(); - } + //private void SectionService_Deleted(ISectionService sender, EventArgs e) + //{ + // _distributedCache.RefreshAllApplicationCache(); + //} - #endregion + //#endregion #region LocalizationService / Dictionary diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 68ac339a46..aab0f9b157 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -18,23 +18,23 @@ namespace Umbraco.Web.Cache #endregion - #region ApplicationTreeCache + //#region ApplicationTreeCache - public static void RefreshAllApplicationTreeCache(this DistributedCache dc) - { - dc.RefreshAll(ApplicationTreeCacheRefresher.UniqueId); - } + //public static void RefreshAllApplicationTreeCache(this DistributedCache dc) + //{ + // dc.RefreshAll(ApplicationTreeCacheRefresher.UniqueId); + //} - #endregion + //#endregion - #region ApplicationCache + //#region ApplicationCache - public static void RefreshAllApplicationCache(this DistributedCache dc) - { - dc.RefreshAll(ApplicationCacheRefresher.UniqueId); - } + //public static void RefreshAllApplicationCache(this DistributedCache dc) + //{ + // dc.RefreshAll(ApplicationCacheRefresher.UniqueId); + //} - #endregion + //#endregion #region User cache diff --git a/src/Umbraco.Web/TagsController.cs b/src/Umbraco.Web/Controllers/TagsController.cs similarity index 89% rename from src/Umbraco.Web/TagsController.cs rename to src/Umbraco.Web/Controllers/TagsController.cs index 181b9f7da2..cb6a28be47 100644 --- a/src/Umbraco.Web/TagsController.cs +++ b/src/Umbraco.Web/Controllers/TagsController.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Services; using Umbraco.Web.Models; using Umbraco.Web.WebApi; -namespace Umbraco.Web.WebServices +namespace Umbraco.Web.Controllers { /// /// A public web service for querying tags @@ -29,8 +29,8 @@ namespace Umbraco.Web.WebServices /// /// Initializes a new instance of the with all its dependencies. /// - public TagsController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public TagsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } /// diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 231ec9ba67..7ffc6e1207 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -52,8 +52,8 @@ namespace Umbraco.Web.Editors /// /// Initializes a new instance of the class with all its dependencies. /// - public AuthenticationController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public AuthenticationController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } protected BackOfficeUserManager UserManager => _userManager diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index ee973a4b58..65ab27d76a 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -14,13 +14,13 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; +using Umbraco.Web.Controllers; using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.PropertyEditors; using Umbraco.Web.Trees; -using Umbraco.Web.WebServices; using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Editors @@ -158,7 +158,7 @@ namespace Umbraco.Web.Editors }, { "treeApplicationApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( - controller => controller.GetApplicationTrees(null, null, null, true)) + controller => controller.GetApplicationTrees(null, null, null)) }, { "contentTypeApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 670d37e7a7..00a0cb90bc 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -54,11 +54,11 @@ namespace Umbraco.Web.Editors public ContentTypeController(IEntityXmlSerializer serializer, ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, - IUmbracoContextAccessor umbracoContextAccessor, + UmbracoContext umbracoContext, ISqlContext sqlContext, PropertyEditorCollection propertyEditors, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) - : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { _serializer = serializer; _propertyEditors = propertyEditors; diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs index 898208319a..a11fcaa869 100644 --- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs @@ -33,7 +33,8 @@ namespace Umbraco.Web.Editors private readonly ICultureDictionaryFactory _cultureDictionaryFactory; private ICultureDictionary _cultureDictionary; - protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { _cultureDictionaryFactory = cultureDictionaryFactory; } diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web/Editors/DashboardController.cs index 8960f110c3..0340926ce4 100644 --- a/src/Umbraco.Web/Editors/DashboardController.cs +++ b/src/Umbraco.Web/Editors/DashboardController.cs @@ -38,8 +38,8 @@ namespace Umbraco.Web.Editors /// /// Initializes a new instance of the with all its dependencies. /// - public DashboardController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { _dashboards = dashboards; } diff --git a/src/Umbraco.Web/Editors/DashboardSecurity.cs b/src/Umbraco.Web/Editors/DashboardSecurity.cs index 1481606c7e..fdbf5af7d9 100644 --- a/src/Umbraco.Web/Editors/DashboardSecurity.cs +++ b/src/Umbraco.Web/Editors/DashboardSecurity.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Configuration.Dashboard; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/Dashboards.cs b/src/Umbraco.Web/Editors/Dashboards.cs index 4bf2d81045..c837cbbf33 100644 --- a/src/Umbraco.Web/Editors/Dashboards.cs +++ b/src/Umbraco.Web/Editors/Dashboards.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Manifest; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 993489855f..c8368d11b0 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -16,11 +16,16 @@ using Constants = Umbraco.Core.Constants; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using System.Web.Http.Controllers; using Examine; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Xml; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Search; +using Umbraco.Web.Services; using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; @@ -37,6 +42,15 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class EntityController : UmbracoAuthorizedJsonController { + private readonly IApplicationTreeService _treeService; + + public EntityController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, + IApplicationTreeService treeService) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) + { + _treeService = treeService; + } + /// /// Configures this controller with a custom action selector /// @@ -129,7 +143,7 @@ namespace Umbraco.Web.Editors { if (allowedSections.Contains(searchableTree.Value.AppAlias)) { - var tree = Services.ApplicationTreeService.GetByAlias(searchableTree.Key); + var tree = _treeService.GetByAlias(searchableTree.Key); if (tree == null) continue; //shouldn't occur var searchableTreeAttribute = searchableTree.Value.SearchableTree.GetType().GetCustomAttribute(false); diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index f2b8fd3dda..e2fbe8c428 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -37,7 +37,8 @@ namespace Umbraco.Web.Editors [MediaTypeControllerControllerConfiguration] public class MediaTypeController : ContentTypeControllerBase { - public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/Editors/MemberTypeController.cs b/src/Umbraco.Web/Editors/MemberTypeController.cs index 3abc0035d3..c59bf6d332 100644 --- a/src/Umbraco.Web/Editors/MemberTypeController.cs +++ b/src/Umbraco.Web/Editors/MemberTypeController.cs @@ -30,7 +30,8 @@ namespace Umbraco.Web.Editors [UmbracoTreeAuthorize(new string[] { Constants.Trees.MemberTypes, Constants.Trees.Members})] public class MemberTypeController : ContentTypeControllerBase { - public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 05d1e2a7a3..ec81b794a1 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -44,10 +44,10 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageInstallController : UmbracoAuthorizedJsonController { - public PackageInstallController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, + public PackageInstallController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs index f650c18fb3..7b484b09b1 100644 --- a/src/Umbraco.Web/Editors/SectionController.cs +++ b/src/Umbraco.Web/Editors/SectionController.cs @@ -2,10 +2,17 @@ using AutoMapper; using Umbraco.Web.Mvc; using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; using Umbraco.Web.Trees; using Section = Umbraco.Web.Models.ContentEditing.Section; using Umbraco.Web.Models.Trees; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { @@ -16,21 +23,32 @@ namespace Umbraco.Web.Editors public class SectionController : UmbracoAuthorizedJsonController { private readonly Dashboards _dashboards; + private readonly ISectionService _sectionService; + private readonly TreeControllerResolver _treeControllerResolver; + private readonly IApplicationTreeService _treeService; - public SectionController(Dashboards dashboards) + public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, + Dashboards dashboards, ISectionService sectionService, TreeControllerResolver treeControllerResolver, IApplicationTreeService treeService) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { _dashboards = dashboards; + _sectionService = sectionService; + _treeControllerResolver = treeControllerResolver; + _treeService = treeService; } public IEnumerable
GetSections() { - var sections = Services.SectionService.GetAllowedSections(Security.GetUserId().ResultOr(0)); + var sections = _sectionService.GetAllowedSections(Security.GetUserId().ResultOr(0)); - var sectionModels = sections.Select(Mapper.Map).ToArray(); + var sectionModels = sections.Select(Mapper.Map
).ToArray(); // this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that // since tree's by nature are controllers and require request contextual data - var appTreeController = new ApplicationTreeController { ControllerContext = ControllerContext }; + var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, ApplicationCache, Logger, RuntimeState, _treeControllerResolver, _treeService) + { + ControllerContext = ControllerContext + }; var dashboards = _dashboards.GetDashboards(Security.CurrentUser); @@ -76,8 +94,8 @@ namespace Umbraco.Web.Editors /// public IEnumerable
GetAllSections() { - var sections = Services.SectionService.GetSections(); - var mapped = sections.Select(Mapper.Map); + var sections = _sectionService.GetSections(); + var mapped = sections.Select(Mapper.Map
); if (Security.CurrentUser.IsAdmin()) return mapped; diff --git a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs index 3baa5e85ff..4e430b833c 100644 --- a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs +++ b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs @@ -31,13 +31,13 @@ namespace Umbraco.Web.Editors /// Initializes a new instance of the class with all its dependencies. ///
/// - /// + /// /// /// /// /// /// - protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } } diff --git a/src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs b/src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs new file mode 100644 index 0000000000..e9befb0e27 --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs @@ -0,0 +1,177 @@ +using System; +using System.Diagnostics; +using Umbraco.Core.Services; + +namespace Umbraco.Web.Models.ContentEditing +{ + [DebuggerDisplay("Tree - {Alias} ({ApplicationAlias})")] + public class ApplicationTree + { + //private static readonly ConcurrentDictionary ResolvedTypes = new ConcurrentDictionary(); + + ///// + ///// Initializes a new instance of the class. + ///// + //public ApplicationTree() { } + + ///// + ///// Initializes a new instance of the class. + ///// + ///// if set to true [initialize]. + ///// The sort order. + ///// The application alias. + ///// The tree alias. + ///// The tree title. + ///// The icon closed. + ///// The icon opened. + ///// The tree type. + //public ApplicationTree(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) + //{ + // //Initialize = initialize; + // SortOrder = sortOrder; + // ApplicationAlias = applicationAlias; + // Alias = alias; + // Title = title; + // IconClosed = iconClosed; + // IconOpened = iconOpened; + // Type = type; + + //} + + public ApplicationTree(int sortOrder, string applicationAlias, string alias, string title) + { + SortOrder = sortOrder; + ApplicationAlias = applicationAlias; + Alias = alias; + Title = title; + } + + ///// + ///// Gets or sets a value indicating whether this should initialize. + ///// + ///// true if initialize; otherwise, false. + //public bool Initialize { get; set; } + + /// + /// Gets or sets the sort order. + /// + /// The sort order. + public int SortOrder { get; set; } + + /// + /// Gets the application alias. + /// + /// The application alias. + public string ApplicationAlias { get; } + + /// + /// Gets the tree alias. + /// + /// The alias. + public string Alias { get; } + + /// + /// Gets or sets the tree title (fallback if the tree alias isn't localized) + /// + /// The title. + public string Title { get; set; } + + ///// + ///// Gets or sets the icon closed. + ///// + ///// The icon closed. + //public string IconClosed { get; set; } + + ///// + ///// Gets or sets the icon opened. + ///// + ///// The icon opened. + //public string IconOpened { get; set; } + + ///// + ///// Gets or sets the tree type assembly name. + ///// + ///// The type. + //public string Type { get; set; } + + /// + /// Returns the localized root node display name + /// + /// + /// + public string GetRootNodeDisplayName(ILocalizedTextService textService) + { + var label = $"[{Alias}]"; + + // try to look up a the localized tree header matching the tree alias + var localizedLabel = textService.Localize("treeHeaders/" + Alias); + + // if the localizedLabel returns [alias] then return the title if it's defined + if (localizedLabel != null && localizedLabel.Equals(label, StringComparison.InvariantCultureIgnoreCase)) + { + if (string.IsNullOrEmpty(Title) == false) + label = Title; + } + else + { + // the localizedLabel translated into something that's not just [alias], so use the translation + label = localizedLabel; + } + + return label; + } + + //private Type _runtimeType; + + ///// + ///// Returns the CLR type based on it's assembly name stored in the config + ///// + ///// + //public Type GetRuntimeType() + //{ + // return _runtimeType ?? (_runtimeType = System.Type.GetType(Type)); + //} + + ///// + ///// Used to try to get and cache the tree type + ///// + ///// + ///// + //internal static Type TryGetType(string type) + //{ + // try + // { + // return ResolvedTypes.GetOrAdd(type, s => + // { + // var result = System.Type.GetType(type); + // if (result != null) + // { + // return result; + // } + + // //we need to implement a bit of a hack here due to some trees being renamed and backwards compat + // var parts = type.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + // if (parts.Length != 2) + // throw new InvalidOperationException("Could not resolve type"); + // if (parts[1].Trim() != "Umbraco.Web" || parts[0].StartsWith("Umbraco.Web.Trees") == false || parts[0].EndsWith("Controller")) + // throw new InvalidOperationException("Could not resolve type"); + + // //if it's one of our controllers but it's not suffixed with "Controller" then add it and try again + // var tempType = parts[0] + "Controller, Umbraco.Web"; + + // result = System.Type.GetType(tempType); + // if (result != null) + // return result; + + // throw new InvalidOperationException("Could not resolve type"); + // }); + // } + // catch (InvalidOperationException) + // { + // //swallow, this is our own exception, couldn't find the type + // // fixme bad use of exceptions here! + // return null; + // } + //} + } +} diff --git a/src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs b/src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs new file mode 100644 index 0000000000..f27941035a --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Models.ContentEditing +{ + + /// + /// Defines a back office section + /// + public interface IBackOfficeSection : IDiscoverable + { + string Alias { get; } + string Name { get; } + int SortOrder { get; } + } +} diff --git a/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs index ba7ff3c38d..683fce36e8 100644 --- a/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using AutoMapper; +using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; @@ -9,7 +10,7 @@ namespace Umbraco.Web.Models.Mapping { public SectionMapperProfile(ILocalizedTextService textService) { - CreateMap() + CreateMap() .ForMember(dest => dest.RoutePath, opt => opt.Ignore()) .ForMember(dest => dest.Icon, opt => opt.Ignore()) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => textService.Localize("sections/" + src.Alias, (IDictionary)null))) diff --git a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs index 8261dda0d4..c975f3a106 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Actions; +using Umbraco.Web.Services; namespace Umbraco.Web.Models.Mapping diff --git a/src/Umbraco.Web/Models/Trees/ApplicationAttribute.cs b/src/Umbraco.Web/Models/Trees/ApplicationAttribute.cs deleted file mode 100644 index 65fc4ed6f3..0000000000 --- a/src/Umbraco.Web/Models/Trees/ApplicationAttribute.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Umbraco.Web.Models.Trees -{ - /// - /// Identifies an application tree - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class ApplicationAttribute : Attribute - { - /// - /// Initializes a new instance of the class. - /// - /// The alias. - /// The name. - /// The sort order. - public ApplicationAttribute(string alias, - string name, - int sortOrder = 0) - { - Alias = alias; - Name = name; - SortOrder = sortOrder; - } - - public string Alias { get; private set; } - public string Name { get; private set; } - public int SortOrder { get; private set; } - } -} diff --git a/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs b/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs index aa8e0cfda6..ba48c9e240 100644 --- a/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs +++ b/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs @@ -1,37 +1,77 @@ using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Trees { - // The application definitions are intended as a means to auto populate - // the application.config. On app startup, Umbraco will look for any - // unregistered classes with an ApplicationAttribute and add them to the cache + /// + /// Defines the back office content section + /// + public class ContentBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Content; + public string Name => "Content"; + public int SortOrder => 0; + } - [Application(Constants.Applications.Content, "Content")] - public class ContentApplicationDefinition : IApplication - { } + /// + /// Defines the back office media section + /// + public class MediaBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Media; + public string Name => "Media"; + public int SortOrder => 1; + } - [Application(Constants.Applications.Media, "Media", sortOrder: 1)] - public class MediaApplicationDefinition : IApplication - { } + /// + /// Defines the back office settings section + /// + public class SettingsBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Settings; + public string Name => "Settings"; + public int SortOrder => 2; + } - [Application(Constants.Applications.Settings, "Settings", sortOrder: 2)] - public class SettingsApplicationDefinition : IApplication - { } + /// + /// Defines the back office packages section + /// + public class PackagesBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Packages; + public string Name => "Packages"; + public int SortOrder => 3; + } - [Application(Constants.Applications.Packages, "Packages", sortOrder: 3)] - public class PackagesApplicationDefinition : IApplication - { } + /// + /// Defines the back office users section + /// + public class UsersBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Users; + public string Name => "Users"; + public int SortOrder => 4; + } - [Application(Constants.Applications.Users, "Users", sortOrder: 4)] - public class UsersApplicationDefinition : IApplication - { } + /// + /// Defines the back office members section + /// + public class MembersBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Members; + public string Name => "Members"; + public int SortOrder => 5; + } - [Application(Constants.Applications.Members, "Members", sortOrder: 5)] - public class MembersApplicationDefinition : IApplication - { } - - [Application(Constants.Applications.Translation, "Translation", sortOrder: 6)] - public class TranslationApplicationDefinition : IApplication - { } + /// + /// Defines the back office translation section + /// + public class TranslationBackOfficeSectionDefinition : IBackOfficeSection + { + public string Alias => Constants.Applications.Translation; + public string Name => "Translation"; + public int SortOrder => 6; + } } diff --git a/src/Umbraco.Web/Models/Trees/IApplication.cs b/src/Umbraco.Web/Models/Trees/IApplication.cs deleted file mode 100644 index 4e9cae43fd..0000000000 --- a/src/Umbraco.Web/Models/Trees/IApplication.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Models.Trees -{ - /// - /// Marker interface for created applications in the umbraco backoffice - /// - public interface IApplication : IDiscoverable - { } -} diff --git a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs b/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs index 30c21fce96..eef6ab1ca2 100644 --- a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs +++ b/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs @@ -8,6 +8,8 @@ namespace Umbraco.Web.Mvc // which we are not doing at the moment // we can inherit from BuilderCollectionBase and just be enumerable + //fixme: this should be LazyCollectionBuilderBase ? + public class SurfaceControllerTypeCollection : BuilderCollectionBase { public SurfaceControllerTypeCollection(IEnumerable items) diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 422b502f80..b7f4e13432 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -22,10 +22,12 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Profiling; using Umbraco.Core.Services; using Umbraco.Web.Install; +using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Security; +using Umbraco.Web.Trees; using Umbraco.Web.UI.JavaScript; using Umbraco.Web.WebApi; diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 51e4fbd008..0ef9adddb7 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -8,6 +8,8 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; +using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -21,6 +23,7 @@ using Umbraco.Web.Dictionary; using Umbraco.Web.Editors; using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; @@ -189,6 +192,14 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append(); + + // register back office sections + composition.WithCollectionBuilder() + .Add(() => composition.TypeLoader.GetTypes()); + + // register back office trees + composition.WithCollectionBuilder() + .Add(() => composition.TypeLoader.GetTypes()); } } } diff --git a/src/Umbraco.Web/Search/SearchableTreeCollection.cs b/src/Umbraco.Web/Search/SearchableTreeCollection.cs index 38c329cafa..2b1baa5194 100644 --- a/src/Umbraco.Web/Search/SearchableTreeCollection.cs +++ b/src/Umbraco.Web/Search/SearchableTreeCollection.cs @@ -5,6 +5,7 @@ using System.Linq; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Services; +using Umbraco.Web.Services; using Umbraco.Web.Trees; namespace Umbraco.Web.Search diff --git a/src/Umbraco.Web/Services/ApplicationTreeService.cs b/src/Umbraco.Web/Services/ApplicationTreeService.cs index 86bfc5d0bb..72b26e26d3 100644 --- a/src/Umbraco.Web/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Web/Services/ApplicationTreeService.cs @@ -11,7 +11,9 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Composing; +using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Services; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Trees; namespace Umbraco.Web.Services @@ -19,276 +21,251 @@ namespace Umbraco.Web.Services internal class ApplicationTreeService : IApplicationTreeService { private readonly ILogger _logger; - private readonly CacheHelper _cache; - private readonly TypeLoader _typeLoader; - private Lazy> _allAvailableTrees; - internal const string TreeConfigFileName = "trees.config"; - private static string _treeConfig; + private readonly TreeCollection _treeCollection; private static readonly object Locker = new object(); private readonly Lazy>> _groupedTrees; - public ApplicationTreeService(ILogger logger, CacheHelper cache, TypeLoader typeLoader) + public ApplicationTreeService(ILogger logger, TreeCollection treeCollection) { _logger = logger; - _cache = cache; - _typeLoader = typeLoader; - _groupedTrees = new Lazy>>(InitGroupedTrees); + _treeCollection = treeCollection; + //_groupedTrees = new Lazy>>(InitGroupedTrees); } - /// - /// gets/sets the trees.config file path - /// - /// - /// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath - /// - internal static string TreeConfigFilePath - { - get - { - if (string.IsNullOrWhiteSpace(_treeConfig)) - { - _treeConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + TreeConfigFileName); - } - return _treeConfig; - } - set { _treeConfig = value; } - } + ///// + ///// gets/sets the trees.config file path + ///// + ///// + ///// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath + ///// + //internal static string TreeConfigFilePath + //{ + // get + // { + // if (string.IsNullOrWhiteSpace(_treeConfig)) + // { + // _treeConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + TreeConfigFileName); + // } + // return _treeConfig; + // } + // set { _treeConfig = value; } + //} - /// - /// The main entry point to get application trees - /// - /// - /// This lazily on first access will scan for plugin trees and ensure the trees.config is up-to-date with the plugins. If plugins - /// haven't changed on disk then the file will not be saved. The trees are all then loaded from this config file into cache and returned. - /// - private List GetAppTrees() - { - return _cache.RuntimeCache.GetCacheItem>( - CacheKeys.ApplicationTreeCacheKey, - () => - { - var list = ReadFromXmlAndSort(); + ///// + ///// The main entry point to get application trees + ///// + ///// + ///// This lazily on first access will scan for plugin trees and ensure the trees.config is up-to-date with the plugins. If plugins + ///// haven't changed on disk then the file will not be saved. The trees are all then loaded from this config file into cache and returned. + ///// + //private List GetAppTrees() + //{ + // return _cache.RuntimeCache.GetCacheItem>( + // CacheKeys.ApplicationTreeCacheKey, + // () => + // { + // var list = ReadFromXmlAndSort(); - //now we can check the non-volatile flag - if (_allAvailableTrees != null) - { - var hasChanges = false; + // //now we can check the non-volatile flag + // if (_allAvailableTrees != null) + // { + // var hasChanges = false; - LoadXml(doc => - { - //Now, load in the xml structure and update it with anything that is not declared there and save the file. + // LoadXml(doc => + // { + // //Now, load in the xml structure and update it with anything that is not declared there and save the file. - //NOTE: On the first iteration here, it will lazily scan all trees, etc... this is because this ienumerable is lazy - // based on the ApplicationTreeRegistrar - and as noted there this is not an ideal way to do things but were stuck like this - // currently because of the legacy assemblies and types not in the Core. + // //NOTE: On the first iteration here, it will lazily scan all trees, etc... this is because this ienumerable is lazy + // // based on the ApplicationTreeRegistrar - and as noted there this is not an ideal way to do things but were stuck like this + // // currently because of the legacy assemblies and types not in the Core. - //Get all the trees not registered in the config (those not matching by alias casing will be detected as "unregistered") - var unregistered = _allAvailableTrees.Value - .Where(x => list.Any(l => l.Alias == x.Alias) == false) - .ToArray(); + // //Get all the trees not registered in the config (those not matching by alias casing will be detected as "unregistered") + // var unregistered = _allAvailableTrees.Value + // .Where(x => list.Any(l => l.Alias == x.Alias) == false) + // .ToArray(); - hasChanges = unregistered.Any(); + // hasChanges = unregistered.Any(); - if (hasChanges == false) return false; + // if (hasChanges == false) return false; - //add or edit the unregistered ones and re-save the file if any changes were found - var count = 0; - foreach (var tree in unregistered) - { - var existingElement = doc.Root.Elements("add").SingleOrDefault(x => - string.Equals(x.Attribute("alias").Value, tree.Alias, - StringComparison.InvariantCultureIgnoreCase) && - string.Equals(x.Attribute("application").Value, tree.ApplicationAlias, - StringComparison.InvariantCultureIgnoreCase)); - if (existingElement != null) - { - existingElement.SetAttributeValue("alias", tree.Alias); - } - else - { - if (tree.Title.IsNullOrWhiteSpace()) - { - doc.Root.Add(new XElement("add", - new XAttribute("initialize", tree.Initialize), - new XAttribute("sortOrder", tree.SortOrder), - new XAttribute("alias", tree.Alias), - new XAttribute("application", tree.ApplicationAlias), - new XAttribute("iconClosed", tree.IconClosed), - new XAttribute("iconOpen", tree.IconOpened), - new XAttribute("type", tree.Type))); - } - else - { - doc.Root.Add(new XElement("add", - new XAttribute("initialize", tree.Initialize), - new XAttribute("sortOrder", tree.SortOrder), - new XAttribute("alias", tree.Alias), - new XAttribute("application", tree.ApplicationAlias), - new XAttribute("title", tree.Title), - new XAttribute("iconClosed", tree.IconClosed), - new XAttribute("iconOpen", tree.IconOpened), - new XAttribute("type", tree.Type))); - } + // //add or edit the unregistered ones and re-save the file if any changes were found + // var count = 0; + // foreach (var tree in unregistered) + // { + // var existingElement = doc.Root.Elements("add").SingleOrDefault(x => + // string.Equals(x.Attribute("alias").Value, tree.Alias, + // StringComparison.InvariantCultureIgnoreCase) && + // string.Equals(x.Attribute("application").Value, tree.ApplicationAlias, + // StringComparison.InvariantCultureIgnoreCase)); + // if (existingElement != null) + // { + // existingElement.SetAttributeValue("alias", tree.Alias); + // } + // else + // { + // if (tree.Title.IsNullOrWhiteSpace()) + // { + // doc.Root.Add(new XElement("add", + // new XAttribute("initialize", tree.Initialize), + // new XAttribute("sortOrder", tree.SortOrder), + // new XAttribute("alias", tree.Alias), + // new XAttribute("application", tree.ApplicationAlias), + // new XAttribute("iconClosed", tree.IconClosed), + // new XAttribute("iconOpen", tree.IconOpened), + // new XAttribute("type", tree.Type))); + // } + // else + // { + // doc.Root.Add(new XElement("add", + // new XAttribute("initialize", tree.Initialize), + // new XAttribute("sortOrder", tree.SortOrder), + // new XAttribute("alias", tree.Alias), + // new XAttribute("application", tree.ApplicationAlias), + // new XAttribute("title", tree.Title), + // new XAttribute("iconClosed", tree.IconClosed), + // new XAttribute("iconOpen", tree.IconOpened), + // new XAttribute("type", tree.Type))); + // } - } - count++; - } + // } + // count++; + // } - //don't save if there's no changes - return count > 0; - }, true); + // //don't save if there's no changes + // return count > 0; + // }, true); - if (hasChanges) - { - //If there were changes, we need to re-read the structures from the XML - list = ReadFromXmlAndSort(); - } - } + // if (hasChanges) + // { + // //If there were changes, we need to re-read the structures from the XML + // list = ReadFromXmlAndSort(); + // } + // } - return list; - }, new TimeSpan(0, 10, 0)); - } + // return list; + // }, new TimeSpan(0, 10, 0)); + //} - /// - /// Creates a new application tree. - /// - /// if set to true [initialize]. - /// The sort order. - /// The application alias. - /// The alias. - /// The title. - /// The icon closed. - /// The icon opened. - /// The type. - public void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) - { - LoadXml(doc => - { - var el = doc.Root.Elements("add").SingleOrDefault(x => x.Attribute("alias").Value == alias && x.Attribute("application").Value == applicationAlias); + ///// + ///// Creates a new application tree. + ///// + ///// if set to true [initialize]. + ///// The sort order. + ///// The application alias. + ///// The alias. + ///// The title. + ///// The icon closed. + ///// The icon opened. + ///// The type. + //public void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) + //{ + // LoadXml(doc => + // { + // var el = doc.Root.Elements("add").SingleOrDefault(x => x.Attribute("alias").Value == alias && x.Attribute("application").Value == applicationAlias); - if (el == null) - { - doc.Root.Add(new XElement("add", - new XAttribute("initialize", initialize), - new XAttribute("sortOrder", sortOrder), - new XAttribute("alias", alias), - new XAttribute("application", applicationAlias), - new XAttribute("title", title), - new XAttribute("iconClosed", iconClosed), - new XAttribute("iconOpen", iconOpened), - new XAttribute("type", type))); - } + // if (el == null) + // { + // doc.Root.Add(new XElement("add", + // new XAttribute("initialize", initialize), + // new XAttribute("sortOrder", sortOrder), + // new XAttribute("alias", alias), + // new XAttribute("application", applicationAlias), + // new XAttribute("title", title), + // new XAttribute("iconClosed", iconClosed), + // new XAttribute("iconOpen", iconOpened), + // new XAttribute("type", type))); + // } - return true; + // return true; - }, true); + // }, true); - OnNew(new ApplicationTree(initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, type), new EventArgs()); - } + // OnNew(new ApplicationTree(initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, type), new EventArgs()); + //} - /// - /// Saves this instance. - /// - public void SaveTree(ApplicationTree tree) - { - LoadXml(doc => - { - var el = doc.Root.Elements("add").SingleOrDefault(x => x.Attribute("alias").Value == tree.Alias && x.Attribute("application").Value == tree.ApplicationAlias); + ///// + ///// Saves this instance. + ///// + //public void SaveTree(ApplicationTree tree) + //{ + // LoadXml(doc => + // { + // var el = doc.Root.Elements("add").SingleOrDefault(x => x.Attribute("alias").Value == tree.Alias && x.Attribute("application").Value == tree.ApplicationAlias); - if (el != null) - { - el.RemoveAttributes(); + // if (el != null) + // { + // el.RemoveAttributes(); - el.Add(new XAttribute("initialize", tree.Initialize)); - el.Add(new XAttribute("sortOrder", tree.SortOrder)); - el.Add(new XAttribute("alias", tree.Alias)); - el.Add(new XAttribute("application", tree.ApplicationAlias)); - el.Add(new XAttribute("title", tree.Title)); - el.Add(new XAttribute("iconClosed", tree.IconClosed)); - el.Add(new XAttribute("iconOpen", tree.IconOpened)); - el.Add(new XAttribute("type", tree.Type)); - } + // el.Add(new XAttribute("initialize", tree.Initialize)); + // el.Add(new XAttribute("sortOrder", tree.SortOrder)); + // el.Add(new XAttribute("alias", tree.Alias)); + // el.Add(new XAttribute("application", tree.ApplicationAlias)); + // el.Add(new XAttribute("title", tree.Title)); + // el.Add(new XAttribute("iconClosed", tree.IconClosed)); + // el.Add(new XAttribute("iconOpen", tree.IconOpened)); + // el.Add(new XAttribute("type", tree.Type)); + // } - return true; + // return true; - }, true); + // }, true); - OnUpdated(tree, new EventArgs()); - } + // OnUpdated(tree, new EventArgs()); + //} - /// - /// Deletes this instance. - /// - public void DeleteTree(ApplicationTree tree) - { - LoadXml(doc => - { - doc.Root.Elements("add") - .Where(x => x.Attribute("application") != null - && x.Attribute("application").Value == tree.ApplicationAlias - && x.Attribute("alias") != null && x.Attribute("alias").Value == tree.Alias).Remove(); + ///// + ///// Deletes this instance. + ///// + //public void DeleteTree(ApplicationTree tree) + //{ + // LoadXml(doc => + // { + // doc.Root.Elements("add") + // .Where(x => x.Attribute("application") != null + // && x.Attribute("application").Value == tree.ApplicationAlias + // && x.Attribute("alias") != null && x.Attribute("alias").Value == tree.Alias).Remove(); - return true; + // return true; - }, true); + // }, true); - OnDeleted(tree, new EventArgs()); - } + // OnDeleted(tree, new EventArgs()); + //} - /// - /// Gets an ApplicationTree by it's tree alias. - /// - /// The tree alias. - /// An ApplicationTree instance - public ApplicationTree GetByAlias(string treeAlias) - { - return GetAppTrees().Find(t => (t.Alias == treeAlias)); + /// + public ApplicationTree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.Alias == treeAlias); - } + /// + public IEnumerable GetAll() => _treeCollection; - /// - /// Gets all applicationTrees registered in umbraco from the umbracoAppTree table.. - /// - /// Returns a ApplicationTree Array - public IEnumerable GetAll() - { - return GetAppTrees().OrderBy(x => x.SortOrder); - } - - /// - /// Gets the application tree for the applcation with the specified alias - /// - /// The application alias. - /// Returns a ApplicationTree Array + /// public IEnumerable GetApplicationTrees(string applicationAlias) - { - return GetApplicationTrees(applicationAlias, false); - } + => GetAll().Where(x => x.ApplicationAlias.InvariantEquals(applicationAlias)).OrderBy(x => x.SortOrder).ToList(); - /// - /// Gets the application tree for the applcation with the specified alias - /// - /// The application alias. - /// - /// Returns a ApplicationTree Array - public IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized) - { - var list = GetAppTrees().FindAll( - t => - { - if (onlyInitialized) - return (t.ApplicationAlias == applicationAlias && t.Initialize); - return (t.ApplicationAlias == applicationAlias); - } - ); + ///// + ///// Gets the application tree for the applcation with the specified alias + ///// + ///// The application alias. + ///// + ///// Returns a ApplicationTree Array + //public IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized) + //{ + // var list = GetAppTrees().FindAll( + // t => + // { + // if (onlyInitialized) + // return (t.ApplicationAlias == applicationAlias && t.Initialize); + // return (t.ApplicationAlias == applicationAlias); + // } + // ); - return list.OrderBy(x => x.SortOrder).ToArray(); - } + // return list.OrderBy(x => x.SortOrder).ToArray(); + //} - public IDictionary> GetGroupedApplicationTrees(string applicationAlias, bool onlyInitialized) + public IDictionary> GetGroupedApplicationTrees(string applicationAlias) { var result = new Dictionary>(); - var foundTrees = GetApplicationTrees(applicationAlias, onlyInitialized); + var foundTrees = GetApplicationTrees(applicationAlias).ToList(); foreach(var treeGroup in _groupedTrees.Value) { List resultGroup = null; @@ -309,185 +286,185 @@ namespace Umbraco.Web.Services return result; } - /// - /// Creates a group of all tree groups and their tree aliases - /// - /// - /// - /// Used to initialize the field - /// - private IReadOnlyCollection> InitGroupedTrees() - { - var result = GetAll() - .Select(x => (treeAlias: x.Alias, treeGroup: x.GetRuntimeType().GetCustomAttribute(false)?.TreeGroup)) - .GroupBy(x => x.treeGroup, x => x.treeAlias) - .ToList(); - return result; - } - - /// - /// Loads in the xml structure from disk if one is found, otherwise loads in an empty xml structure, calls the - /// callback with the xml document and saves the structure back to disk if saveAfterCallback is true. - /// - /// - /// - internal void LoadXml(Func callback, bool saveAfterCallbackIfChanges) - { - lock (Locker) - { - var doc = System.IO.File.Exists(TreeConfigFilePath) - ? XDocument.Load(TreeConfigFilePath) - : XDocument.Parse(""); + ///// + ///// Creates a group of all tree groups and their tree aliases + ///// + ///// + ///// + ///// Used to initialize the field + ///// + //private IReadOnlyCollection> InitGroupedTrees() + //{ + // var result = GetAll() + // .Select(x => (treeAlias: x.Alias, treeGroup: x.GetRuntimeType().GetCustomAttribute(false)?.TreeGroup)) + // .GroupBy(x => x.treeGroup, x => x.treeAlias) + // .ToList(); + // return result; + //} - if (doc.Root != null) - { - var hasChanges = callback.Invoke(doc); + ///// + ///// Loads in the xml structure from disk if one is found, otherwise loads in an empty xml structure, calls the + ///// callback with the xml document and saves the structure back to disk if saveAfterCallback is true. + ///// + ///// + ///// + //internal void LoadXml(Func callback, bool saveAfterCallbackIfChanges) + //{ + // lock (Locker) + // { + // var doc = System.IO.File.Exists(TreeConfigFilePath) + // ? XDocument.Load(TreeConfigFilePath) + // : XDocument.Parse(""); - if (saveAfterCallbackIfChanges && hasChanges - //Don't save it if it is empty, in some very rare cases if the app domain get's killed in the middle of this process - // in some insane way the file saved will be empty. I'm pretty sure it's not actually anything to do with the xml doc and - // more about the IO trying to save the XML doc, but it doesn't hurt to check. - && doc.Root != null && doc.Root.Elements().Any()) - { - //ensures the folder exists - Directory.CreateDirectory(Path.GetDirectoryName(TreeConfigFilePath)); + // if (doc.Root != null) + // { + // var hasChanges = callback.Invoke(doc); - //saves it - doc.Save(TreeConfigFilePath); + // if (saveAfterCallbackIfChanges && hasChanges + // //Don't save it if it is empty, in some very rare cases if the app domain get's killed in the middle of this process + // // in some insane way the file saved will be empty. I'm pretty sure it's not actually anything to do with the xml doc and + // // more about the IO trying to save the XML doc, but it doesn't hurt to check. + // && doc.Root != null && doc.Root.Elements().Any()) + // { + // //ensures the folder exists + // Directory.CreateDirectory(Path.GetDirectoryName(TreeConfigFilePath)); - //remove the cache now that it has changed SD: I'm leaving this here even though it - // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); - } - } - } - } + // //saves it + // doc.Save(TreeConfigFilePath); - private List ReadFromXmlAndSort() - { - var list = new List(); + // //remove the cache now that it has changed SD: I'm leaving this here even though it + // // is taken care of by events as well, I think unit tests may rely on it being cleared here. + // _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + // } + // } + // } + //} - //read in the xml file containing trees and convert them all to ApplicationTree instances - LoadXml(doc => - { - foreach (var addElement in doc.Root.Elements("add").OrderBy(x => - { - var sortOrderAttr = x.Attribute("sortOrder"); - return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0; - })) - { - var applicationAlias = (string)addElement.Attribute("application"); - var type = (string)addElement.Attribute("type"); - var assembly = (string)addElement.Attribute("assembly"); + //private List ReadFromXmlAndSort() + //{ + // var list = new List(); - var clrType = Type.GetType(type); - if (clrType == null) - { - _logger.Warn("The tree definition: {AddElement} could not be resolved to a .Net object type", addElement); - continue; - } + // //read in the xml file containing trees and convert them all to ApplicationTree instances + // LoadXml(doc => + // { + // foreach (var addElement in doc.Root.Elements("add").OrderBy(x => + // { + // var sortOrderAttr = x.Attribute("sortOrder"); + // return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0; + // })) + // { + // var applicationAlias = (string)addElement.Attribute("application"); + // var type = (string)addElement.Attribute("type"); + // var assembly = (string)addElement.Attribute("assembly"); - //check if the tree definition (applicationAlias + type + assembly) is already in the list + // var clrType = Type.GetType(type); + // if (clrType == null) + // { + // _logger.Warn("The tree definition: {AddElement} could not be resolved to a .Net object type", addElement); + // continue; + // } - if (list.Any(tree => tree.ApplicationAlias.InvariantEquals(applicationAlias) && tree.GetRuntimeType() == clrType) == false) - { - list.Add(new ApplicationTree( - addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value), - addElement.Attribute("sortOrder") != null - ? Convert.ToByte(addElement.Attribute("sortOrder").Value) - : (byte)0, - (string)addElement.Attribute("application"), - (string)addElement.Attribute("alias"), - (string)addElement.Attribute("title"), - (string)addElement.Attribute("iconClosed"), - (string)addElement.Attribute("iconOpen"), - (string)addElement.Attribute("type"))); - } - } + // //check if the tree definition (applicationAlias + type + assembly) is already in the list - return false; + // if (list.Any(tree => tree.ApplicationAlias.InvariantEquals(applicationAlias) && tree.GetRuntimeType() == clrType) == false) + // { + // list.Add(new ApplicationTree( + // addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value), + // addElement.Attribute("sortOrder") != null + // ? Convert.ToByte(addElement.Attribute("sortOrder").Value) + // : (byte)0, + // (string)addElement.Attribute("application"), + // (string)addElement.Attribute("alias"), + // (string)addElement.Attribute("title"), + // (string)addElement.Attribute("iconClosed"), + // (string)addElement.Attribute("iconOpen"), + // (string)addElement.Attribute("type"))); + // } + // } - }, false); + // return false; - return list; - } + // }, false); + + // return list; + //} - internal static event TypedEventHandler Deleted; - private static void OnDeleted(ApplicationTree app, EventArgs args) - { - if (Deleted != null) - { - Deleted(app, args); - } - } + //internal static event TypedEventHandler Deleted; + //private static void OnDeleted(ApplicationTree app, EventArgs args) + //{ + // if (Deleted != null) + // { + // Deleted(app, args); + // } + //} - internal static event TypedEventHandler New; - private static void OnNew(ApplicationTree app, EventArgs args) - { - if (New != null) - { - New(app, args); - } - } + //internal static event TypedEventHandler New; + //private static void OnNew(ApplicationTree app, EventArgs args) + //{ + // if (New != null) + // { + // New(app, args); + // } + //} - internal static event TypedEventHandler Updated; - private static void OnUpdated(ApplicationTree app, EventArgs args) - { - if (Updated != null) - { - Updated(app, args); - } - } + //internal static event TypedEventHandler Updated; + //private static void OnUpdated(ApplicationTree app, EventArgs args) + //{ + // if (Updated != null) + // { + // Updated(app, args); + // } + //} - /// - /// This class is here so that we can provide lazy access to tree scanning for when it is needed - /// - private class LazyEnumerableTrees : IEnumerable - { - public LazyEnumerableTrees(TypeLoader typeLoader) - { - _lazyTrees = new Lazy>(() => - { - var added = new List(); + ///// + ///// This class is here so that we can provide lazy access to tree scanning for when it is needed + ///// + //private class LazyEnumerableTrees : IEnumerable + //{ + // public LazyEnumerableTrees(TypeLoader typeLoader) + // { + // _lazyTrees = new Lazy>(() => + // { + // var added = new List(); - // Load all Controller Trees by attribute - var types = typeLoader.GetTypesWithAttribute(); // fixme inject - //convert them to ApplicationTree instances - var items = types - .Select(x => (tree: x, treeAttribute: x.GetCustomAttributes(false).Single())) - .Select(x => new ApplicationTree(x.treeAttribute.Initialize, x.treeAttribute.SortOrder, x.treeAttribute.ApplicationAlias, x.treeAttribute.Alias, x.treeAttribute.Title, x.treeAttribute.IconClosed, x.treeAttribute.IconOpen, x.tree.GetFullNameWithAssembly())) - .ToArray(); + // // Load all Controller Trees by attribute + // var types = typeLoader.GetTypesWithAttribute(); // fixme inject + // //convert them to ApplicationTree instances + // var items = types + // .Select(x => (tree: x, treeAttribute: x.GetCustomAttributes(false).Single())) + // .Select(x => new ApplicationTree(x.treeAttribute.Initialize, x.treeAttribute.SortOrder, x.treeAttribute.ApplicationAlias, x.treeAttribute.Alias, x.treeAttribute.Title, x.treeAttribute.IconClosed, x.treeAttribute.IconOpen, x.tree.GetFullNameWithAssembly())) + // .ToArray(); - added.AddRange(items.Select(x => x.Alias)); + // added.AddRange(items.Select(x => x.Alias)); - return items.ToArray(); - }); - } + // return items.ToArray(); + // }); + // } - private readonly Lazy> _lazyTrees; - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return _lazyTrees.Value.GetEnumerator(); - } + // private readonly Lazy> _lazyTrees; - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } + // /// + // /// Returns an enumerator that iterates through the collection. + // /// + // /// + // /// A that can be used to iterate through the collection. + // /// + // public IEnumerator GetEnumerator() + // { + // return _lazyTrees.Value.GetEnumerator(); + // } + + // /// + // /// Returns an enumerator that iterates through a collection. + // /// + // /// + // /// An object that can be used to iterate through the collection. + // /// + // IEnumerator IEnumerable.GetEnumerator() + // { + // return GetEnumerator(); + // } + //} } } diff --git a/src/Umbraco.Core/Services/IApplicationTreeService.cs b/src/Umbraco.Web/Services/IApplicationTreeService.cs similarity index 52% rename from src/Umbraco.Core/Services/IApplicationTreeService.cs rename to src/Umbraco.Web/Services/IApplicationTreeService.cs index 691a3a0b63..1fd7bc939a 100644 --- a/src/Umbraco.Core/Services/IApplicationTreeService.cs +++ b/src/Umbraco.Web/Services/IApplicationTreeService.cs @@ -2,33 +2,35 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Core.Services +namespace Umbraco.Web.Services { public interface IApplicationTreeService { - /// - /// Creates a new application tree. - /// - /// if set to true [initialize]. - /// The sort order. - /// The application alias. - /// The alias. - /// The title. - /// The icon closed. - /// The icon opened. - /// The type. - void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type); + ///// + ///// Creates a new application tree. + ///// + ///// if set to true [initialize]. + ///// The sort order. + ///// The application alias. + ///// The alias. + ///// The title. + ///// The icon closed. + ///// The icon opened. + ///// The type. + //void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type); - /// - /// Saves this instance. - /// - void SaveTree(ApplicationTree tree); + ///// + ///// Saves this instance. + ///// + //void SaveTree(ApplicationTree tree); - /// - /// Deletes this instance. - /// - void DeleteTree(ApplicationTree tree); + ///// + ///// Deletes this instance. + ///// + //void DeleteTree(ApplicationTree tree); /// /// Gets an ApplicationTree by it's tree alias. @@ -50,21 +52,20 @@ namespace Umbraco.Core.Services /// Returns a ApplicationTree Array IEnumerable GetApplicationTrees(string applicationAlias); - /// - /// Gets the application tree for the applcation with the specified alias - /// - /// The application alias. - /// - /// Returns a ApplicationTree Array - IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized); + ///// + ///// Gets the application tree for the applcation with the specified alias + ///// + ///// The application alias. + ///// + ///// Returns a ApplicationTree Array + //IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized); /// /// Gets the grouped application trees for the application with the specified alias /// /// - /// /// - IDictionary> GetGroupedApplicationTrees(string applicationAlias, bool onlyInitialized); + IDictionary> GetGroupedApplicationTrees(string applicationAlias); } /// @@ -72,37 +73,37 @@ namespace Umbraco.Core.Services /// internal class EmptyApplicationTreeService : IApplicationTreeService { - /// - /// Creates a new application tree. - /// - /// if set to true [initialize]. - /// The sort order. - /// The application alias. - /// The alias. - /// The title. - /// The icon closed. - /// The icon opened. - /// The type. - public void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) - { - throw new System.NotImplementedException(); - } + ///// + ///// Creates a new application tree. + ///// + ///// if set to true [initialize]. + ///// The sort order. + ///// The application alias. + ///// The alias. + ///// The title. + ///// The icon closed. + ///// The icon opened. + ///// The type. + //public void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) + //{ + // throw new System.NotImplementedException(); + //} - /// - /// Saves this instance. - /// - public void SaveTree(ApplicationTree tree) - { - throw new System.NotImplementedException(); - } + ///// + ///// Saves this instance. + ///// + //public void SaveTree(ApplicationTree tree) + //{ + // throw new System.NotImplementedException(); + //} - /// - /// Deletes this instance. - /// - public void DeleteTree(ApplicationTree tree) - { - throw new System.NotImplementedException(); - } + ///// + ///// Deletes this instance. + ///// + //public void DeleteTree(ApplicationTree tree) + //{ + // throw new System.NotImplementedException(); + //} /// /// Gets an ApplicationTree by it's tree alias. @@ -123,7 +124,7 @@ namespace Umbraco.Core.Services throw new System.NotImplementedException(); } - public IDictionary> GetGroupedApplicationTrees(string applicationAlias, bool onlyInitialized) + public IDictionary> GetGroupedApplicationTrees(string applicationAlias) { throw new System.NotImplementedException(); } diff --git a/src/Umbraco.Web/Services/ISectionService.cs b/src/Umbraco.Web/Services/ISectionService.cs new file mode 100644 index 0000000000..560805634f --- /dev/null +++ b/src/Umbraco.Web/Services/ISectionService.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.Services +{ + public interface ISectionService + { + /// + /// The cache storage for all applications + /// + IEnumerable GetSections(); + + /// + /// Get the user group's allowed sections + /// + /// + /// + IEnumerable GetAllowedSections(int userId); + + /// + /// Gets the application by its alias. + /// + /// The application alias. + /// + IBackOfficeSection GetByAlias(string appAlias); + + ///// + ///// Creates a new applcation if no application with the specified alias is found. + ///// + ///// The application name. + ///// The application alias. + ///// The application icon, which has to be located in umbraco/images/tray folder. + //void MakeNew(string name, string alias, string icon); + + ///// + ///// Makes the new. + ///// + ///// The name. + ///// The alias. + ///// The icon. + ///// The sort order. + //void MakeNew(string name, string alias, string icon, int sortOrder); + + ///// + ///// Deletes the section + ///// + //void DeleteSection(Section section); + } + + /// + /// Purely used to allow a service context to create the default services + /// + internal class EmptySectionService : ISectionService + { + /// + /// The cache storage for all applications + /// + public IEnumerable GetSections() + { + throw new System.NotImplementedException(); + } + + /// + /// Get the user's allowed sections + /// + /// + /// + public IEnumerable GetAllowedSections(int userId) + { + throw new System.NotImplementedException(); + } + + /// + /// Gets the application by its alias. + /// + /// The application alias. + /// + public IBackOfficeSection GetByAlias(string appAlias) + { + throw new System.NotImplementedException(); + } + + ///// + ///// Creates a new applcation if no application with the specified alias is found. + ///// + ///// The application name. + ///// The application alias. + ///// The application icon, which has to be located in umbraco/images/tray folder. + //public void MakeNew(string name, string alias, string icon) + //{ + // throw new System.NotImplementedException(); + //} + + ///// + ///// Makes the new. + ///// + ///// The name. + ///// The alias. + ///// The icon. + ///// The sort order. + //public void MakeNew(string name, string alias, string icon, int sortOrder) + //{ + // throw new System.NotImplementedException(); + //} + + ///// + ///// Deletes the section + ///// + //public void DeleteSection(IBackOfficeSection section) + //{ + // throw new System.NotImplementedException(); + //} + } +} diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index 6337db67f9..bb154976f0 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -10,9 +10,12 @@ using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Composing; +using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Scoping; using Umbraco.Core.Services; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Trees; +using Umbraco.Web.Trees; using File = System.IO.File; namespace Umbraco.Web.Services @@ -20,130 +23,90 @@ namespace Umbraco.Web.Services internal class SectionService : ISectionService { private readonly IUserService _userService; - private readonly Lazy> _allAvailableSections; - private readonly IApplicationTreeService _applicationTreeService; - private readonly IScopeProvider _scopeProvider; + private readonly BackOfficeSectionCollection _sectionCollection; + + private readonly Lazy> _allAvailableSections; + //private readonly IApplicationTreeService _applicationTreeService; + //private readonly IScopeProvider _scopeProvider; private readonly CacheHelper _cache; - internal const string AppConfigFileName = "applications.config"; - private static string _appConfig; - private static readonly object Locker = new object(); + //internal const string AppConfigFileName = "applications.config"; + //private static string _appConfig; + //private static readonly object Locker = new object(); public SectionService( IUserService userService, - IApplicationTreeService applicationTreeService, - IScopeProvider scopeProvider, + BackOfficeSectionCollection sectionCollection, CacheHelper cache) { - _applicationTreeService = applicationTreeService ?? throw new ArgumentNullException(nameof(applicationTreeService)); + //_applicationTreeService = applicationTreeService ?? throw new ArgumentNullException(nameof(applicationTreeService)); _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _userService = userService; - _scopeProvider = scopeProvider; - _allAvailableSections = new Lazy>(() => new LazyEnumerableSections()); + _sectionCollection = sectionCollection; + //_scopeProvider = scopeProvider; + //_allAvailableSections = new Lazy>(() => new LazyEnumerableSections()); } - /// - /// gets/sets the application.config file path - /// - /// - /// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath - /// - internal static string AppConfigFilePath - { - get - { - if (string.IsNullOrWhiteSpace(_appConfig)) - { - _appConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + AppConfigFileName); - } - return _appConfig; - } - set => _appConfig = value; - } + ///// + ///// gets/sets the application.config file path + ///// + ///// + ///// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath + ///// + //internal static string AppConfigFilePath + //{ + // get + // { + // if (string.IsNullOrWhiteSpace(_appConfig)) + // { + // _appConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + AppConfigFileName); + // } + // return _appConfig; + // } + // set => _appConfig = value; + //} /// /// The cache storage for all applications /// - public IEnumerable
GetSections() + public IEnumerable GetSections() { - return _cache.RuntimeCache.GetCacheItem>( - CacheKeys.ApplicationsCacheKey, - () => - { - var list = ReadFromXmlAndSort(); - var hasChanges = false; - var localCopyList = list; - - LoadXml(doc => - { - //Now, load in the xml structure and update it with anything that is not declared there and save the file. - //NOTE: On the first iteration here, it will lazily scan all apps, etc... this is because this ienumerable is lazy - //Get all the trees not registered in the config - - var unregistered = _allAvailableSections.Value - .Where(x => localCopyList.Any(l => l.Alias == x.Alias) == false) - .ToArray(); - - hasChanges = unregistered.Any(); - - var count = 0; - foreach (var attr in unregistered) - { - doc.Root.Add(new XElement("add", - new XAttribute("alias", attr.Alias), - new XAttribute("name", attr.Name), - new XAttribute("sortOrder", attr.SortOrder))); - count++; - } - - //don't save if there's no changes - return count > 0; - }, true); - - if (hasChanges) - { - //If there were changes, we need to re-read the structures from the XML - list = ReadFromXmlAndSort(); - } - - return list; - - }, new TimeSpan(0, 10, 0)); + return _sectionCollection; } - internal void LoadXml(Func callback, bool saveAfterCallbackIfChanged) - { - lock (Locker) - { - var doc = File.Exists(AppConfigFilePath) - ? XDocument.Load(AppConfigFilePath) - : XDocument.Parse(""); + //internal void LoadXml(Func callback, bool saveAfterCallbackIfChanged) + //{ + // lock (Locker) + // { + // var doc = File.Exists(AppConfigFilePath) + // ? XDocument.Load(AppConfigFilePath) + // : XDocument.Parse(""); - if (doc.Root != null) - { - var changed = callback.Invoke(doc); + // if (doc.Root != null) + // { + // var changed = callback.Invoke(doc); - if (saveAfterCallbackIfChanged && changed) - { - //ensure the folder is created! - Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath)); + // if (saveAfterCallbackIfChanged && changed) + // { + // //ensure the folder is created! + // Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath)); - doc.Save(AppConfigFilePath); + // doc.Save(AppConfigFilePath); - //remove the cache so it gets re-read ... SD: I'm leaving this here even though it - // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); - } - } - } - } + // //remove the cache so it gets re-read ... SD: I'm leaving this here even though it + // // is taken care of by events as well, I think unit tests may rely on it being cleared here. + // _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + // } + // } + // } + //} /// /// Get the user's allowed sections /// /// /// - public IEnumerable
GetAllowedSections(int userId) + public IEnumerable GetAllowedSections(int userId) { var user = _userService.GetUserById(userId); @@ -160,172 +123,172 @@ namespace Umbraco.Web.Services ///
/// The application alias. /// - public Section GetByAlias(string appAlias) + public IBackOfficeSection GetByAlias(string appAlias) { return GetSections().FirstOrDefault(t => t.Alias == appAlias); } - /// - /// Creates a new applcation if no application with the specified alias is found. - /// - /// The application name. - /// The application alias. - /// The application icon, which has to be located in umbraco/images/tray folder. - public void MakeNew(string name, string alias, string icon) - { - var sections = GetSections(); - var nextSortOrder = sections.Any() ? sections.Max(x => x.SortOrder) + 1 : 1; - MakeNew(name, alias, icon, nextSortOrder); - } + ///// + ///// Creates a new applcation if no application with the specified alias is found. + ///// + ///// The application name. + ///// The application alias. + ///// The application icon, which has to be located in umbraco/images/tray folder. + //public void MakeNew(string name, string alias, string icon) + //{ + // var sections = GetSections(); + // var nextSortOrder = sections.Any() ? sections.Max(x => x.SortOrder) + 1 : 1; + // MakeNew(name, alias, icon, nextSortOrder); + //} - /// - /// Makes the new. - /// - /// The name. - /// The alias. - /// The icon. - /// The sort order. - public void MakeNew(string name, string alias, string icon, int sortOrder) - { - if (GetSections().All(x => x.Alias != alias)) - { - LoadXml(doc => - { - doc.Root.Add(new XElement("add", - new XAttribute("alias", alias), - new XAttribute("name", name), - new XAttribute("icon", icon), - new XAttribute("sortOrder", sortOrder))); - return true; - }, true); + ///// + ///// Makes the new. + ///// + ///// The name. + ///// The alias. + ///// The icon. + ///// The sort order. + //public void MakeNew(string name, string alias, string icon, int sortOrder) + //{ + // if (GetSections().All(x => x.Alias != alias)) + // { + // LoadXml(doc => + // { + // doc.Root.Add(new XElement("add", + // new XAttribute("alias", alias), + // new XAttribute("name", name), + // new XAttribute("icon", icon), + // new XAttribute("sortOrder", sortOrder))); + // return true; + // }, true); - //raise event - OnNew(this /*new Section(name, alias, sortOrder)*/, new EventArgs()); - } - } + // //raise event + // OnNew(this /*new Section(name, alias, sortOrder)*/, new EventArgs()); + // } + //} - /// - /// Deletes the section - /// - public void DeleteSection(Section section) - { - lock (Locker) - { - //delete the assigned applications - using (var scope = _scopeProvider.CreateScope()) - { - scope.Database.Execute("delete from umbracoUserGroup2App where app = @appAlias", - new { appAlias = section.Alias }); - scope.Complete(); - } + ///// + ///// Deletes the section + ///// + //public void DeleteSection(Section section) + //{ + // lock (Locker) + // { + // //delete the assigned applications + // using (var scope = _scopeProvider.CreateScope()) + // { + // scope.Database.Execute("delete from umbracoUserGroup2App where app = @appAlias", + // new { appAlias = section.Alias }); + // scope.Complete(); + // } - //delete the assigned trees - var trees = _applicationTreeService.GetApplicationTrees(section.Alias); - foreach (var t in trees) - { - _applicationTreeService.DeleteTree(t); - } + // //delete the assigned trees + // var trees = _applicationTreeService.GetApplicationTrees(section.Alias); + // foreach (var t in trees) + // { + // _applicationTreeService.DeleteTree(t); + // } - LoadXml(doc => - { - doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias) - .Remove(); + // LoadXml(doc => + // { + // doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias) + // .Remove(); - return true; - }, true); + // return true; + // }, true); - //raise event - OnDeleted(this, new EventArgs()); - } - } + // //raise event + // OnDeleted(this, new EventArgs()); + // } + //} - private List
ReadFromXmlAndSort() - { - var tmp = new List
(); + //private List
ReadFromXmlAndSort() + //{ + // var tmp = new List
(); - LoadXml(doc => - { - foreach (var addElement in doc.Root.Elements("add").OrderBy(x => - { - var sortOrderAttr = x.Attribute("sortOrder"); - return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0; - })) - { - var sortOrderAttr = addElement.Attribute("sortOrder"); - tmp.Add(new Section(addElement.Attribute("name").Value, - addElement.Attribute("alias").Value, - sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0)); - } - return false; - }, false); + // LoadXml(doc => + // { + // foreach (var addElement in doc.Root.Elements("add").OrderBy(x => + // { + // var sortOrderAttr = x.Attribute("sortOrder"); + // return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0; + // })) + // { + // var sortOrderAttr = addElement.Attribute("sortOrder"); + // tmp.Add(new Section(addElement.Attribute("name").Value, + // addElement.Attribute("alias").Value, + // sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0)); + // } + // return false; + // }, false); - return tmp; - } + // return tmp; + //} - internal static event TypedEventHandler Deleted; - private static void OnDeleted(ISectionService app, EventArgs args) - { - if (Deleted != null) - { - Deleted(app, args); - } - } + //internal static event TypedEventHandler Deleted; + //private static void OnDeleted(ISectionService app, EventArgs args) + //{ + // if (Deleted != null) + // { + // Deleted(app, args); + // } + //} - internal static event TypedEventHandler New; - private static void OnNew(ISectionService app, EventArgs args) - { - if (New != null) - { - New(app, args); - } - } + //internal static event TypedEventHandler New; + //private static void OnNew(ISectionService app, EventArgs args) + //{ + // if (New != null) + // { + // New(app, args); + // } + //} - /// - /// This class is here so that we can provide lazy access to tree scanning for when it is needed - /// - private class LazyEnumerableSections : IEnumerable
- { - public LazyEnumerableSections() - { - _lazySections = new Lazy>(() => - { - // Load all Applications by attribute and add them to the XML config + ///// + ///// This class is here so that we can provide lazy access to tree scanning for when it is needed + ///// + //private class LazyEnumerableSections : IEnumerable
+ //{ + // public LazyEnumerableSections() + // { + // _lazySections = new Lazy>(() => + // { + // // Load all Applications by attribute and add them to the XML config - //don't cache the result of this because it is only used once during app startup, caching will just add a bit more mem overhead for no reason - var types = Current.TypeLoader.GetTypesWithAttribute(cache: false); // fixme - inject + // //don't cache the result of this because it is only used once during app startup, caching will just add a bit more mem overhead for no reason + // var types = Current.TypeLoader.GetTypesWithAttribute(cache: false); // fixme - inject - //since applications don't populate their metadata from the attribute and because it is an interface, - //we need to interrogate the attributes for the data. Would be better to have a base class that contains - //metadata populated by the attribute. Oh well i guess. - var attrs = types.Select(x => x.GetCustomAttributes(false).Single()); - return attrs.Select(x => new Section(x.Name, x.Alias, x.SortOrder)).ToArray(); - }); - } + // //since applications don't populate their metadata from the attribute and because it is an interface, + // //we need to interrogate the attributes for the data. Would be better to have a base class that contains + // //metadata populated by the attribute. Oh well i guess. + // var attrs = types.Select(x => x.GetCustomAttributes(false).Single()); + // return attrs.Select(x => new Section(x.Name, x.Alias, x.SortOrder)).ToArray(); + // }); + // } - private readonly Lazy> _lazySections; + // private readonly Lazy> _lazySections; - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator
GetEnumerator() - { - return _lazySections.Value.GetEnumerator(); - } + // /// + // /// Returns an enumerator that iterates through the collection. + // /// + // /// + // /// A that can be used to iterate through the collection. + // /// + // public IEnumerator
GetEnumerator() + // { + // return _lazySections.Value.GetEnumerator(); + // } - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } + // /// + // /// Returns an enumerator that iterates through a collection. + // /// + // /// + // /// An object that can be used to iterate through the collection. + // /// + // IEnumerator IEnumerable.GetEnumerator() + // { + // return GetEnumerator(); + // } + //} } } diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 0454155772..7e7c77d607 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -7,10 +7,17 @@ using System.Net.Http.Formatting; using System.Threading.Tasks; using System.Web.Http; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; +using Umbraco.Web.Services; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; @@ -20,7 +27,19 @@ namespace Umbraco.Web.Trees [AngularJsonOnlyConfiguration] [PluginController("UmbracoTrees")] public class ApplicationTreeController : UmbracoAuthorizedApiController - { + { + private readonly TreeControllerResolver _treeControllerResolver; + private readonly IApplicationTreeService _treeService; + + public ApplicationTreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, + ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, + IRuntimeState runtimeState, TreeControllerResolver treeControllerResolver, IApplicationTreeService treeService) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) + { + _treeControllerResolver = treeControllerResolver; + _treeService = treeService; + } + /// /// Returns the tree nodes for an application /// @@ -30,14 +49,14 @@ namespace Umbraco.Web.Trees /// An optional bool (defaults to true), if set to false it will also load uninitialized trees /// [HttpQueryStringFilter("queryStrings")] - public async Task GetApplicationTrees(string application, string tree, FormDataCollection queryStrings, bool onlyInitialized = true) + public async Task GetApplicationTrees(string application, string tree, FormDataCollection queryStrings/*, bool onlyInitialized = true*/) { application = application.CleanForXss(); if (string.IsNullOrEmpty(application)) throw new HttpResponseException(HttpStatusCode.NotFound); //find all tree definitions that have the current application alias - var groupedTrees = Services.ApplicationTreeService.GetGroupedApplicationTrees(application, onlyInitialized); + var groupedTrees = _treeService.GetGroupedApplicationTrees(application); var allTrees = groupedTrees.Values.SelectMany(x => x).ToList(); if (string.IsNullOrEmpty(tree) == false || allTrees.Count == 1) @@ -142,7 +161,7 @@ namespace Umbraco.Web.Trees if (configTree == null) throw new ArgumentNullException(nameof(configTree)); try { - var byControllerAttempt = await configTree.TryGetRootNodeFromControllerTree(queryStrings, ControllerContext); + var byControllerAttempt = await _treeControllerResolver.TryGetRootNodeFromControllerTree(configTree, queryStrings, ControllerContext); if (byControllerAttempt.Success) { return byControllerAttempt.Result; @@ -170,17 +189,17 @@ namespace Umbraco.Web.Trees { var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture); if (configTree == null) throw new ArgumentNullException(nameof(configTree)); - var byControllerAttempt = configTree.TryLoadFromControllerTree(id, queryStrings, ControllerContext); + var byControllerAttempt = _treeControllerResolver.TryLoadFromControllerTree(configTree, id, queryStrings, ControllerContext); if (byControllerAttempt.Success) { - var rootNode = await configTree.TryGetRootNodeFromControllerTree(queryStrings, ControllerContext); + var rootNode = await _treeControllerResolver.TryGetRootNodeFromControllerTree(configTree, queryStrings, ControllerContext); if (rootNode.Success == false) { //This should really never happen if we've successfully got the children above. throw new InvalidOperationException("Could not create root node for tree " + configTree.Alias); } - var treeAttribute = configTree.GetTreeAttribute(); + var treeAttribute = _treeControllerResolver.GetTreeAttribute(configTree); var sectionRoot = TreeRootNode.CreateSingleTreeRoot( rootId, diff --git a/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs b/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs new file mode 100644 index 0000000000..2b5a78d758 --- /dev/null +++ b/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Umbraco.Core.Composing; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.Trees +{ + public class BackOfficeSectionCollection : BuilderCollectionBase + { + public BackOfficeSectionCollection(IEnumerable items) + : base(items) + { } + } + + public class BackOfficeSectionCollectionBuilder : LazyCollectionBuilderBase + { + protected override BackOfficeSectionCollectionBuilder This => this; + + //TODO: can we allow for re-ordering OOTB without exposing other methods? + } +} diff --git a/src/Umbraco.Web/Trees/TreeCollection.cs b/src/Umbraco.Web/Trees/TreeCollection.cs new file mode 100644 index 0000000000..8f913fb2d7 --- /dev/null +++ b/src/Umbraco.Web/Trees/TreeCollection.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core.Composing; +using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.Trees +{ + public class TreeCollection : BuilderCollectionBase + { + public TreeCollection(IEnumerable items) + : base(items) + { } + } + + public class TreeCollectionBuilder : LazyCollectionBuilderBase + { + protected override TreeCollectionBuilder This => this; + + //TODO: can we allow for re-ordering OOTB without exposing other methods? + } + +} diff --git a/src/Umbraco.Web/Trees/TreeController.cs b/src/Umbraco.Web/Trees/TreeController.cs index 1c37307db5..102671ec29 100644 --- a/src/Umbraco.Web/Trees/TreeController.cs +++ b/src/Umbraco.Web/Trees/TreeController.cs @@ -1,4 +1,12 @@ -namespace Umbraco.Web.Trees +using System; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; + +namespace Umbraco.Web.Trees { /// /// The base controller for all tree requests @@ -8,6 +16,10 @@ private TreeAttribute _attribute; private string _rootNodeDisplayName; + protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) + { + } + protected TreeController() { Initialize(); @@ -17,21 +29,25 @@ /// The name to display on the root node /// public override string RootNodeDisplayName - => _rootNodeDisplayName - ?? (_rootNodeDisplayName = Services.ApplicationTreeService.GetByAlias(_attribute.Alias) - ?.GetRootNodeDisplayName(Services.TextService)); + { + get + { + throw new NotImplementedException(); + //return _rootNodeDisplayName + // ?? (_rootNodeDisplayName = Services.ApplicationTreeService.GetByAlias(_attribute.Alias) + // ?.GetRootNodeDisplayName(Services.TextService)); + } + } /// /// Gets the current tree alias from the attribute assigned to it. /// - public override string TreeAlias - { - get { return _attribute.Alias; } - } + public override string TreeAlias => _attribute.Alias; private void Initialize() { - _attribute = GetType().GetTreeAttribute(); + throw new NotImplementedException(); + //_attribute = GetType().GetTreeAttribute(); } } } diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs index ffdcac4479..c00d6053c8 100644 --- a/src/Umbraco.Web/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs @@ -4,9 +4,14 @@ using System.Linq; using System.Net.Http.Formatting; using System.Web.Http.Routing; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration; using Umbraco.Core.Events; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; using Umbraco.Web.Models.Trees; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; @@ -14,12 +19,23 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Trees { /// - /// A base controller reference for non-attributed trees (un-registered). Developers should inherit from - /// TreeController. + /// A base controller reference for non-attributed trees (un-registered). /// + /// + /// Developers should generally inherit from TreeController. + /// [AngularJsonOnlyConfiguration] public abstract class TreeControllerBase : UmbracoAuthorizedApiController { + protected TreeControllerBase() + { + } + + protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) + { + } + + /// /// The method called to render the contents of the tree structure /// @@ -351,7 +367,7 @@ namespace Umbraco.Web.Trees private static void OnTreeNodesRendering(TreeControllerBase instance, TreeNodesRenderingEventArgs e) { var handler = TreeNodesRendering; - if (handler != null) handler(instance, e); + handler?.Invoke(instance, e); } /// @@ -363,7 +379,7 @@ namespace Umbraco.Web.Trees internal static void OnRootNodeRendering(TreeControllerBase instance, TreeNodeRenderingEventArgs e) { var handler = RootNodeRendering; - if (handler != null) handler(instance, e); + handler?.Invoke(instance, e); } /// @@ -377,80 +393,8 @@ namespace Umbraco.Web.Trees private static void OnMenuRendering(TreeControllerBase instance, MenuRenderingEventArgs e) { var handler = MenuRendering; - if (handler != null) handler(instance, e); + handler?.Invoke(instance, e); } } - internal class TreeControllerBaseStuffForLegacy - { - private readonly string _treeAlias; - private readonly string _rootNodeDisplayName; - private readonly UrlHelper _url; - - public TreeControllerBaseStuffForLegacy(string treeAlias, string rootNodeDisplayName, UrlHelper url) - { - _treeAlias = treeAlias; - _rootNodeDisplayName = rootNodeDisplayName; - _url = url; - } - - public TreeNode GetRootNode(FormDataCollection queryStrings) - { - if (queryStrings == null) queryStrings = new FormDataCollection(""); - var node = CreateRootNode(queryStrings); - - //add the tree alias to the root - node.AdditionalData["treeAlias"] = _treeAlias; - - AddQueryStringsToAdditionalData(node, queryStrings); - - //check if the tree is searchable and add that to the meta data as well - if (this is ISearchableTree) - { - node.AdditionalData.Add("searchable", "true"); - } - - //now update all data based on some of the query strings, like if we are running in dialog mode - if (IsDialog(queryStrings)) - { - node.RoutePath = "#"; - } - - TreeControllerBase.OnRootNodeRendering(null, new TreeNodeRenderingEventArgs(node, queryStrings)); - - return node; - } - - protected virtual TreeNode CreateRootNode(FormDataCollection queryStrings) - { - var rootNodeAsString = Constants.System.Root.ToString(CultureInfo.InvariantCulture); - var currApp = queryStrings.GetValue(TreeQueryStringParameters.Application); - - var node = new TreeNode( - rootNodeAsString, - null, //this is a root node, there is no parent - _url.GetTreeUrl(GetType(), rootNodeAsString, queryStrings), - _url.GetMenuUrl(GetType(), rootNodeAsString, queryStrings)) - { - HasChildren = true, - RoutePath = currApp, - Name = _rootNodeDisplayName - }; - - return node; - } - - protected void AddQueryStringsToAdditionalData(TreeNode node, FormDataCollection queryStrings) - { - foreach (var q in queryStrings.Where(x => node.AdditionalData.ContainsKey(x.Key) == false)) - { - node.AdditionalData.Add(q.Key, q.Value); - } - } - - protected bool IsDialog(FormDataCollection queryStrings) - { - return queryStrings.GetValue(TreeQueryStringParameters.IsDialog); - } - } } diff --git a/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs b/src/Umbraco.Web/Trees/TreeControllerResolver.cs similarity index 56% rename from src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs rename to src/Umbraco.Web/Trees/TreeControllerResolver.cs index 2c43cbd5dc..62cafbb5dd 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs +++ b/src/Umbraco.Web/Trees/TreeControllerResolver.cs @@ -14,16 +14,25 @@ using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Core.Composing; -using Current = Umbraco.Web.Composing.Current; -using ApplicationTree = Umbraco.Core.Models.ApplicationTree; +using ApplicationTree = Umbraco.Web.Models.ContentEditing.ApplicationTree; namespace Umbraco.Web.Trees { - internal static class ApplicationTreeExtensions + public class TreeControllerResolver { - private static readonly ConcurrentDictionary TreeAttributeCache = new ConcurrentDictionary(); + private readonly TreeCollection _trees; + private readonly UmbracoApiControllerTypeCollection _apiControllers; - internal static TreeAttribute GetTreeAttribute(this Type treeControllerType) + public TreeControllerResolver(TreeCollection trees, UmbracoApiControllerTypeCollection apiControllers) + { + _trees = trees; + _apiControllers = apiControllers; + } + + private static readonly ConcurrentDictionary TreeAttributeCache = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary ResolvedControllerTypes = new ConcurrentDictionary(); + + private TreeAttribute GetTreeAttribute(Type treeControllerType) { return TreeAttributeCache.GetOrAdd(treeControllerType, type => { @@ -42,25 +51,41 @@ namespace Umbraco.Web.Trees }); } - internal static TreeAttribute GetTreeAttribute(this ApplicationTree tree) + internal TreeAttribute GetTreeAttribute(ApplicationTree tree) { - return tree.GetRuntimeType().GetTreeAttribute(); + throw new NotImplementedException(); + //return ResolvedControllerTypes.GetOrAdd(tree.Alias, s => + //{ + // var controllerType = _apiControllers + // .OfType() + // .FirstOrDefault(x => x.) + //}); + + //return GetTreeAttribute(tree.GetRuntimeType()); } - internal static Attempt TryGetControllerTree(this ApplicationTree appTree) + private Type GetControllerType(ApplicationTree tree) { - //get reference to all TreeApiControllers - var controllerTrees = Current.UmbracoApiControllerTypes - .Where(TypeHelper.IsTypeAssignableFrom) - .ToArray(); + throw new NotImplementedException(); + } + - //find the one we're looking for - var foundControllerTree = controllerTrees.FirstOrDefault(x => x == appTree.GetRuntimeType()); - if (foundControllerTree == null) - { - return Attempt.Fail(new InstanceNotFoundException("Could not find tree of type " + appTree.Type + " in any loaded DLLs")); - } - return Attempt.Succeed(foundControllerTree); + internal Attempt TryGetControllerTree(ApplicationTree appTree) + { + throw new NotImplementedException(); + + ////get reference to all TreeApiControllers + //var controllerTrees = _apiControllers + // .Where(TypeHelper.IsTypeAssignableFrom) + // .ToArray(); + + ////find the one we're looking for + //var foundControllerTree = controllerTrees.FirstOrDefault(x => x == appTree.GetRuntimeType()); + //if (foundControllerTree == null) + //{ + // return Attempt.Fail(new InstanceNotFoundException("Could not find tree of type " + appTree.Type + " in any loaded DLLs")); + //} + //return Attempt.Succeed(foundControllerTree); } /// @@ -73,9 +98,9 @@ namespace Umbraco.Web.Trees /// /// This ensures that authorization filters are applied to the sub request /// - internal static async Task> TryGetRootNodeFromControllerTree(this ApplicationTree appTree, FormDataCollection formCollection, HttpControllerContext controllerContext) + internal async Task> TryGetRootNodeFromControllerTree(ApplicationTree appTree, FormDataCollection formCollection, HttpControllerContext controllerContext) { - var foundControllerTreeAttempt = appTree.TryGetControllerTree(); + var foundControllerTreeAttempt = TryGetControllerTree(appTree); if (foundControllerTreeAttempt.Success == false) { return Attempt.Fail(foundControllerTreeAttempt.Exception); @@ -110,12 +135,15 @@ namespace Umbraco.Web.Trees if (WebApiVersionCheck.WebApiVersion >= Version.Parse("5.0.0")) { - //In WebApi2, this is required to be set: - // proxiedControllerContext.RequestContext = controllerContext.RequestContext - // but we need to do this with reflection because of codebase changes between version 4/5 - //NOTE: Use TypeHelper here since the reflection is cached - var controllerContextRequestContext = TypeHelper.GetProperty(controllerContext.GetType(), "RequestContext").GetValue(controllerContext); - TypeHelper.GetProperty(proxiedControllerContext.GetType(), "RequestContext").SetValue(proxiedControllerContext, controllerContextRequestContext); + //fixme - will this 'just' work now? + proxiedControllerContext.RequestContext = controllerContext.RequestContext; + + ////In WebApi2, this is required to be set: + //// proxiedControllerContext.RequestContext = controllerContext.RequestContext + //// but we need to do this with reflection because of codebase changes between version 4/5 + ////NOTE: Use TypeHelper here since the reflection is cached + //var controllerContextRequestContext = TypeHelper.GetProperty(controllerContext.GetType(), "RequestContext").GetValue(controllerContext); + //TypeHelper.GetProperty(proxiedControllerContext.GetType(), "RequestContext").SetValue(proxiedControllerContext, controllerContextRequestContext); } instance.ControllerContext = proxiedControllerContext; @@ -123,13 +151,17 @@ namespace Umbraco.Web.Trees if (WebApiVersionCheck.WebApiVersion >= Version.Parse("5.0.0")) { - //now we can change the request context's route data to be the proxied route data - NOTE: we cannot do this directly above - // because it will detect that the request context is different throw an exception. This is a change in webapi2 and we need to set - // this with reflection due to codebase changes between version 4/5 - // instance.RequestContext.RouteData = proxiedRouteData; - //NOTE: Use TypeHelper here since the reflection is cached - var instanceRequestContext = TypeHelper.GetProperty(typeof(ApiController), "RequestContext").GetValue(instance); - TypeHelper.GetProperty(instanceRequestContext.GetType(), "RouteData").SetValue(instanceRequestContext, proxiedRouteData); + + //fixme - will this 'just' work now? + instance.RequestContext.RouteData = proxiedRouteData; + + ////now we can change the request context's route data to be the proxied route data - NOTE: we cannot do this directly above + //// because it will detect that the request context is different throw an exception. This is a change in webapi2 and we need to set + //// this with reflection due to codebase changes between version 4/5 + //// instance.RequestContext.RouteData = proxiedRouteData; + ////NOTE: Use TypeHelper here since the reflection is cached + //var instanceRequestContext = TypeHelper.GetProperty(typeof(ApiController), "RequestContext").GetValue(instance); + //TypeHelper.GetProperty(instanceRequestContext.GetType(), "RouteData").SetValue(instanceRequestContext, proxiedRouteData); } //invoke auth filters for this sub request @@ -143,13 +175,13 @@ namespace Umbraco.Web.Trees //return the root var node = instance.GetRootNode(formCollection); return node == null - ? Attempt.Fail(new InvalidOperationException("Could not return a root node for tree " + appTree.Type)) + ? Attempt.Fail(new InvalidOperationException("Could not return a root node for tree " + appTree.Alias)) : Attempt.Succeed(node); } - internal static Attempt TryLoadFromControllerTree(this ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext) + internal Attempt TryLoadFromControllerTree(ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext) { - var foundControllerTreeAttempt = appTree.TryGetControllerTree(); + var foundControllerTreeAttempt = TryGetControllerTree(appTree); if (foundControllerTreeAttempt.Success == false) return Attempt.Fail(foundControllerTreeAttempt.Exception); diff --git a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs index bb9ce3c421..9e632eabc9 100644 --- a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs +++ b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs @@ -29,12 +29,14 @@ namespace Umbraco.Web.UI.Pages var treeAuth = this.GetType().GetCustomAttribute(true); if (treeAuth != null) { - var treeByAlias = Current.Services.ApplicationTreeService - .GetByAlias(treeAuth.TreeAlias); - if (treeByAlias != null) - { - CurrentApp = treeByAlias.ApplicationAlias; - } + throw new NotImplementedException(); + + //var treeByAlias = Current.Services.ApplicationTreeService + // .GetByAlias(treeAuth.TreeAlias); + //if (treeByAlias != null) + //{ + // CurrentApp = treeByAlias.ApplicationAlias; + //} } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b0142771d2..f1d15e9ea6 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -166,6 +166,8 @@ + + @@ -181,6 +183,9 @@ + + + @@ -217,6 +222,7 @@ + @@ -585,9 +591,7 @@ - - @@ -890,7 +894,6 @@ - @@ -969,7 +972,7 @@ - + @@ -1236,7 +1239,7 @@ True Reference.map - + diff --git a/src/Umbraco.Web/UrlHelperExtensions.cs b/src/Umbraco.Web/UrlHelperExtensions.cs index 9b1c282aab..0a04539967 100644 --- a/src/Umbraco.Web/UrlHelperExtensions.cs +++ b/src/Umbraco.Web/UrlHelperExtensions.cs @@ -13,7 +13,6 @@ using Umbraco.Web.Composing; using Umbraco.Web.Editors; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Web.WebServices; namespace Umbraco.Web { diff --git a/src/Umbraco.Web/WebApi/Filters/LegacyTreeAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/LegacyTreeAuthorizeAttribute.cs deleted file mode 100644 index 5d1b90a09d..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/LegacyTreeAuthorizeAttribute.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Web.Http; -using System.Web.Http.Controllers; -using Umbraco.Core; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.WebApi.Filters -{ - internal class LegacyTreeAuthorizeAttribute : AuthorizeAttribute - { - protected override bool IsAuthorized(HttpActionContext actionContext) - { - var httpContext = actionContext.Request.TryGetHttpContext(); - if (httpContext) - { - var treeRequest = httpContext.Result.Request.QueryString["treeType"]; - if (treeRequest.IsNullOrWhiteSpace()) return false; - - var tree = Current.Services.ApplicationTreeService.GetByAlias(treeRequest); - if (tree == null) return false; - - return UmbracoContext.Current.Security.CurrentUser != null - && UmbracoContext.Current.Security.UserHasSectionAccess(tree.ApplicationAlias, UmbracoContext.Current.Security.CurrentUser); - } - return false; - - - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs index 7318c9d9b8..cc483db416 100644 --- a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Core; @@ -40,16 +41,18 @@ namespace Umbraco.Web.WebApi.Filters return true; } - var apps = _treeAliases.Select(x => Current.Services.ApplicationTreeService - .GetByAlias(x)) - .WhereNotNull() - .Select(x => x.ApplicationAlias) - .Distinct() - .ToArray(); + throw new NotImplementedException(); - return Current.UmbracoContext.Security.CurrentUser != null - && apps.Any(app => Current.UmbracoContext.Security.UserHasSectionAccess( - app, Current.UmbracoContext.Security.CurrentUser)); + //var apps = _treeAliases.Select(x => Current.Services.ApplicationTreeService + // .GetByAlias(x)) + // .WhereNotNull() + // .Select(x => x.ApplicationAlias) + // .Distinct() + // .ToArray(); + + //return Current.UmbracoContext.Security.CurrentUser != null + // && apps.Any(app => Current.UmbracoContext.Security.UserHasSectionAccess( + // app, Current.UmbracoContext.Security.CurrentUser)); } } } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index 3db3610cc2..586160cfa0 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -23,8 +23,8 @@ namespace Umbraco.Web.WebApi /// /// Initialize a new instance of the with all its dependencies. /// - protected UmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + protected UmbracoApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } } } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs index 21b88cc919..106ef60e0b 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs @@ -21,7 +21,6 @@ namespace Umbraco.Web.WebApi [FeatureAuthorize] public abstract class UmbracoApiControllerBase : ApiController { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; private UmbracoHelper _umbracoHelper; // note: all Umbraco controllers have two constructors: one with all dependencies, which should be used, @@ -36,7 +35,7 @@ namespace Umbraco.Web.WebApi protected UmbracoApiControllerBase() : this( Current.Factory.GetInstance(), - Current.Factory.GetInstance(), + Current.Factory.GetInstance().UmbracoContext, Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), @@ -48,15 +47,15 @@ namespace Umbraco.Web.WebApi /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoApiControllerBase(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + protected UmbracoApiControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) { GlobalSettings = globalSettings; - _umbracoContextAccessor = umbracoContextAccessor; SqlContext = sqlContext; Services = services; ApplicationCache = applicationCache; Logger = logger; RuntimeState = runtimeState; + UmbracoContext = umbracoContext; } /// @@ -73,8 +72,8 @@ namespace Umbraco.Web.WebApi /// /// Gets the Umbraco context. /// - public virtual UmbracoContext UmbracoContext => _umbracoContextAccessor.UmbracoContext; - + public virtual UmbracoContext UmbracoContext { get; } + /// /// Gets the sql context. /// diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs index cdb1aa2f51..d84ab3fe4a 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs @@ -8,6 +8,8 @@ namespace Umbraco.Web.WebApi // which we are not doing at the moment // we can inherit from BuilderCollectionBase and just be enumerable + //fixme: this should be LazyCollectionBuilderBase ? + public class UmbracoApiControllerTypeCollection : BuilderCollectionBase { public UmbracoApiControllerTypeCollection(IEnumerable items) diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 4ae9c00a47..e8c0a3c674 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -40,8 +40,8 @@ namespace Umbraco.Web.WebApi /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { } /// diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs index 26116820e6..c6d5ba30d9 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs @@ -1,61 +1,61 @@ -using System; -using System.Xml; -using System.Xml.Linq; -using Umbraco.Core; -using Umbraco.Core._Legacy.PackageActions; -using Umbraco.Web.Composing; +//using System; +//using System.Xml; +//using System.Xml.Linq; +//using Umbraco.Core; +//using Umbraco.Core._Legacy.PackageActions; +//using Umbraco.Web.Composing; -namespace Umbraco.Web._Legacy.PackageActions -{ - /// - /// This class implements the IPackageAction Interface, used to execute code when packages are installed. - /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. - /// - public class AddApplication : IPackageAction - { +//namespace Umbraco.Web._Legacy.PackageActions +//{ +// /// +// /// This class implements the IPackageAction Interface, used to execute code when packages are installed. +// /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. +// /// +// public class AddApplication : IPackageAction +// { - #region IPackageAction Members +// #region IPackageAction Members - /// - /// Installs a new application in umbraco. - /// - /// Name of the package. - /// The XML data. - /// - /// - /// - /// true if successfull - public bool Execute(string packageName, XElement xmlData) - { - string name = xmlData.AttributeValue("appName"); - string alias = xmlData.AttributeValue("appAlias"); - string icon = xmlData.AttributeValue("appIcon"); +// /// +// /// Installs a new application in umbraco. +// /// +// /// Name of the package. +// /// The XML data. +// /// +// /// +// /// +// /// true if successfull +// public bool Execute(string packageName, XElement xmlData) +// { +// string name = xmlData.AttributeValue("appName"); +// string alias = xmlData.AttributeValue("appAlias"); +// string icon = xmlData.AttributeValue("appIcon"); - Current.Services.SectionService.MakeNew(name, alias, icon); +// Current.Services.SectionService.MakeNew(name, alias, icon); - return true; - } +// return true; +// } - public bool Undo(string packageName, XElement xmlData) - { - string alias = xmlData.AttributeValue("appAlias"); - var section = Current.Services.SectionService.GetByAlias(alias); - if (section != null) - { - Current.Services.SectionService.DeleteSection(section); - } - return true; - } - /// - /// Action alias. - /// - /// - public string Alias() - { - return "addApplication"; - } +// public bool Undo(string packageName, XElement xmlData) +// { +// string alias = xmlData.AttributeValue("appAlias"); +// var section = Current.Services.SectionService.GetByAlias(alias); +// if (section != null) +// { +// Current.Services.SectionService.DeleteSection(section); +// } +// return true; +// } +// /// +// /// Action alias. +// /// +// /// +// public string Alias() +// { +// return "addApplication"; +// } - #endregion +// #endregion - } -} +// } +//} From cfe1b17eecc5a06b56530610d9e04158033e66a4 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 16:40:11 +1100 Subject: [PATCH 145/223] Gets trees and sections loading now in a much more simplified way without any xml, now to cleanup --- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 2 +- src/Umbraco.Web/Composing/Current.cs | 7 + .../Editors/BackOfficeServerVariables.cs | 2 +- src/Umbraco.Web/Editors/EntityController.cs | 6 +- src/Umbraco.Web/Editors/SectionController.cs | 8 +- .../Models/ContentEditing/ApplicationTree.cs | 177 --------------- .../Mvc/SurfaceControllerTypeCollection.cs | 4 +- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 13 +- .../Search/SearchableTreeCollection.cs | 8 +- .../Services/IApplicationTreeService.cs | 153 ------------- src/Umbraco.Web/Services/ISectionService.cs | 89 +------- src/Umbraco.Web/Services/ITreeService.cs | 49 +++++ ...plicationTreeService.cs => TreeService.cs} | 40 ++-- src/Umbraco.Web/Trees/ApplicationTree.cs | 69 ++++++ .../Trees/ApplicationTreeController.cs | 173 +++++++++++---- src/Umbraco.Web/Trees/ITree.cs | 31 +++ src/Umbraco.Web/Trees/TreeAttribute.cs | 35 +-- src/Umbraco.Web/Trees/TreeCollection.cs | 21 +- src/Umbraco.Web/Trees/TreeController.cs | 55 +++-- src/Umbraco.Web/Trees/TreeControllerBase.cs | 14 +- .../Trees/TreeControllerResolver.cs | 203 ------------------ .../Trees/UserPermissionsTreeController.cs | 52 ----- src/Umbraco.Web/Umbraco.Web.csproj | 10 +- .../Filters/UmbracoTreeAuthorizeAttribute.cs | 20 +- src/Umbraco.Web/WebApi/MvcVersionCheck.cs | 10 - .../UmbracoApiControllerTypeCollection.cs | 2 - 26 files changed, 425 insertions(+), 828 deletions(-) delete mode 100644 src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs delete mode 100644 src/Umbraco.Web/Services/IApplicationTreeService.cs create mode 100644 src/Umbraco.Web/Services/ITreeService.cs rename src/Umbraco.Web/Services/{ApplicationTreeService.cs => TreeService.cs} (95%) create mode 100644 src/Umbraco.Web/Trees/ApplicationTree.cs create mode 100644 src/Umbraco.Web/Trees/ITree.cs delete mode 100644 src/Umbraco.Web/Trees/TreeControllerResolver.cs delete mode 100644 src/Umbraco.Web/Trees/UserPermissionsTreeController.cs delete mode 100644 src/Umbraco.Web/WebApi/MvcVersionCheck.cs diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index a79531af74..0a0999f2dc 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -342,7 +342,7 @@ namespace Umbraco.Tests.Testing Composition.ComposeServices(); // composition root is doing weird things, fix - Composition.RegisterUnique(); + Composition.RegisterUnique(); Composition.RegisterUnique(); // somehow property editor ends up wanting this diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 1e8f3d17f7..d887720063 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -25,6 +25,7 @@ using Umbraco.Web.HealthCheck; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using Umbraco.Web.Services; using Umbraco.Web.WebApi; using CoreCurrent = Umbraco.Core.Composing.Current; @@ -135,6 +136,12 @@ namespace Umbraco.Web.Composing internal static IPublishedSnapshotService PublishedSnapshotService => Factory.GetInstance(); + public static ITreeService TreeService + => Factory.GetInstance(); + + public static ISectionService SectionService + => Factory.GetInstance(); + #endregion #region Web Constants diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 65ab27d76a..1525dd5808 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -408,7 +408,7 @@ namespace Umbraco.Web.Editors let pluginAttr = p.attributes.OfType().Single() select new Dictionary { - {"alias", treeAttr.Alias}, {"packageFolder", pluginAttr.AreaName} + {"alias", treeAttr.TreeAlias}, {"packageFolder", pluginAttr.AreaName} }).ToArray(); } diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index c8368d11b0..ca1a6a12bb 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -42,10 +42,10 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class EntityController : UmbracoAuthorizedJsonController { - private readonly IApplicationTreeService _treeService; + private readonly ITreeService _treeService; public EntityController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, - IApplicationTreeService treeService) + ITreeService treeService) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { _treeService = treeService; @@ -148,7 +148,7 @@ namespace Umbraco.Web.Editors var searchableTreeAttribute = searchableTree.Value.SearchableTree.GetType().GetCustomAttribute(false); - result[tree.GetRootNodeDisplayName(Services.TextService)] = new TreeSearchResult + result[ApplicationTree.GetRootNodeDisplayName(tree, Services.TextService)] = new TreeSearchResult { Results = searchableTree.Value.SearchableTree.Search(query, 200, 0, out var total), TreeAlias = searchableTree.Key, diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs index 7b484b09b1..d68f062f61 100644 --- a/src/Umbraco.Web/Editors/SectionController.cs +++ b/src/Umbraco.Web/Editors/SectionController.cs @@ -24,16 +24,14 @@ namespace Umbraco.Web.Editors { private readonly Dashboards _dashboards; private readonly ISectionService _sectionService; - private readonly TreeControllerResolver _treeControllerResolver; - private readonly IApplicationTreeService _treeService; + private readonly ITreeService _treeService; public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, - Dashboards dashboards, ISectionService sectionService, TreeControllerResolver treeControllerResolver, IApplicationTreeService treeService) + Dashboards dashboards, ISectionService sectionService, ITreeService treeService) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { _dashboards = dashboards; _sectionService = sectionService; - _treeControllerResolver = treeControllerResolver; _treeService = treeService; } @@ -45,7 +43,7 @@ namespace Umbraco.Web.Editors // this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that // since tree's by nature are controllers and require request contextual data - var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, ApplicationCache, Logger, RuntimeState, _treeControllerResolver, _treeService) + var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, ApplicationCache, Logger, RuntimeState, _treeService) { ControllerContext = ControllerContext }; diff --git a/src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs b/src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs deleted file mode 100644 index e9befb0e27..0000000000 --- a/src/Umbraco.Web/Models/ContentEditing/ApplicationTree.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Diagnostics; -using Umbraco.Core.Services; - -namespace Umbraco.Web.Models.ContentEditing -{ - [DebuggerDisplay("Tree - {Alias} ({ApplicationAlias})")] - public class ApplicationTree - { - //private static readonly ConcurrentDictionary ResolvedTypes = new ConcurrentDictionary(); - - ///// - ///// Initializes a new instance of the class. - ///// - //public ApplicationTree() { } - - ///// - ///// Initializes a new instance of the class. - ///// - ///// if set to true [initialize]. - ///// The sort order. - ///// The application alias. - ///// The tree alias. - ///// The tree title. - ///// The icon closed. - ///// The icon opened. - ///// The tree type. - //public ApplicationTree(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) - //{ - // //Initialize = initialize; - // SortOrder = sortOrder; - // ApplicationAlias = applicationAlias; - // Alias = alias; - // Title = title; - // IconClosed = iconClosed; - // IconOpened = iconOpened; - // Type = type; - - //} - - public ApplicationTree(int sortOrder, string applicationAlias, string alias, string title) - { - SortOrder = sortOrder; - ApplicationAlias = applicationAlias; - Alias = alias; - Title = title; - } - - ///// - ///// Gets or sets a value indicating whether this should initialize. - ///// - ///// true if initialize; otherwise, false. - //public bool Initialize { get; set; } - - /// - /// Gets or sets the sort order. - /// - /// The sort order. - public int SortOrder { get; set; } - - /// - /// Gets the application alias. - /// - /// The application alias. - public string ApplicationAlias { get; } - - /// - /// Gets the tree alias. - /// - /// The alias. - public string Alias { get; } - - /// - /// Gets or sets the tree title (fallback if the tree alias isn't localized) - /// - /// The title. - public string Title { get; set; } - - ///// - ///// Gets or sets the icon closed. - ///// - ///// The icon closed. - //public string IconClosed { get; set; } - - ///// - ///// Gets or sets the icon opened. - ///// - ///// The icon opened. - //public string IconOpened { get; set; } - - ///// - ///// Gets or sets the tree type assembly name. - ///// - ///// The type. - //public string Type { get; set; } - - /// - /// Returns the localized root node display name - /// - /// - /// - public string GetRootNodeDisplayName(ILocalizedTextService textService) - { - var label = $"[{Alias}]"; - - // try to look up a the localized tree header matching the tree alias - var localizedLabel = textService.Localize("treeHeaders/" + Alias); - - // if the localizedLabel returns [alias] then return the title if it's defined - if (localizedLabel != null && localizedLabel.Equals(label, StringComparison.InvariantCultureIgnoreCase)) - { - if (string.IsNullOrEmpty(Title) == false) - label = Title; - } - else - { - // the localizedLabel translated into something that's not just [alias], so use the translation - label = localizedLabel; - } - - return label; - } - - //private Type _runtimeType; - - ///// - ///// Returns the CLR type based on it's assembly name stored in the config - ///// - ///// - //public Type GetRuntimeType() - //{ - // return _runtimeType ?? (_runtimeType = System.Type.GetType(Type)); - //} - - ///// - ///// Used to try to get and cache the tree type - ///// - ///// - ///// - //internal static Type TryGetType(string type) - //{ - // try - // { - // return ResolvedTypes.GetOrAdd(type, s => - // { - // var result = System.Type.GetType(type); - // if (result != null) - // { - // return result; - // } - - // //we need to implement a bit of a hack here due to some trees being renamed and backwards compat - // var parts = type.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - // if (parts.Length != 2) - // throw new InvalidOperationException("Could not resolve type"); - // if (parts[1].Trim() != "Umbraco.Web" || parts[0].StartsWith("Umbraco.Web.Trees") == false || parts[0].EndsWith("Controller")) - // throw new InvalidOperationException("Could not resolve type"); - - // //if it's one of our controllers but it's not suffixed with "Controller" then add it and try again - // var tempType = parts[0] + "Controller, Umbraco.Web"; - - // result = System.Type.GetType(tempType); - // if (result != null) - // return result; - - // throw new InvalidOperationException("Could not resolve type"); - // }); - // } - // catch (InvalidOperationException) - // { - // //swallow, this is our own exception, couldn't find the type - // // fixme bad use of exceptions here! - // return null; - // } - //} - } -} diff --git a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs b/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs index eef6ab1ca2..d9577417cc 100644 --- a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs +++ b/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs @@ -7,9 +7,7 @@ namespace Umbraco.Web.Mvc // unless we want to modify the content of the collection // which we are not doing at the moment // we can inherit from BuilderCollectionBase and just be enumerable - - //fixme: this should be LazyCollectionBuilderBase ? - + public class SurfaceControllerTypeCollection : BuilderCollectionBase { public SurfaceControllerTypeCollection(IEnumerable items) diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 0ef9adddb7..047d080a88 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -95,7 +95,7 @@ namespace Umbraco.Web.Runtime // replace some services composition.RegisterUnique(); composition.RegisterUnique(); - composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(factory => ExamineManager.Instance); @@ -125,9 +125,11 @@ namespace Umbraco.Web.Runtime composition.WithCollectionBuilder() .Add(() => composition.TypeLoader.GetTypes()); + //we need to eagerly scan controller types since they will need to be routed var surfaceControllerTypes = new SurfaceControllerTypeCollection(composition.TypeLoader.GetSurfaceControllers()); composition.RegisterUnique(surfaceControllerTypes); + //we need to eagerly scan controller types since they will need to be routed var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(composition.TypeLoader.GetUmbracoApiControllers()); composition.RegisterUnique(umbracoApiControllerTypes); @@ -198,8 +200,13 @@ namespace Umbraco.Web.Runtime .Add(() => composition.TypeLoader.GetTypes()); // register back office trees - composition.WithCollectionBuilder() - .Add(() => composition.TypeLoader.GetTypes()); + foreach (var treeControllerType in umbracoApiControllerTypes) + { + var attribute = treeControllerType.GetCustomAttribute(false); + if (attribute == null) continue; + var tree = new ApplicationTree(attribute.SortOrder, attribute.ApplicationAlias, attribute.TreeAlias, attribute.TreeTitle, treeControllerType, attribute.IsSingleNodeTree); + composition.WithCollectionBuilder().AddTree(tree); + } } } } diff --git a/src/Umbraco.Web/Search/SearchableTreeCollection.cs b/src/Umbraco.Web/Search/SearchableTreeCollection.cs index 2b1baa5194..032782b466 100644 --- a/src/Umbraco.Web/Search/SearchableTreeCollection.cs +++ b/src/Umbraco.Web/Search/SearchableTreeCollection.cs @@ -14,13 +14,13 @@ namespace Umbraco.Web.Search { private readonly Dictionary _dictionary; - public SearchableTreeCollection(IEnumerable items, IApplicationTreeService treeService) + public SearchableTreeCollection(IEnumerable items, ITreeService treeService) : base(items) { _dictionary = CreateDictionary(treeService); } - private Dictionary CreateDictionary(IApplicationTreeService treeService) + private Dictionary CreateDictionary(ITreeService treeService) { var appTrees = treeService.GetAll() .OrderBy(x => x.SortOrder) @@ -29,10 +29,10 @@ namespace Umbraco.Web.Search var searchableTrees = this.ToArray(); foreach (var appTree in appTrees) { - var found = searchableTrees.FirstOrDefault(x => x.TreeAlias.InvariantEquals(appTree.Alias)); + var found = searchableTrees.FirstOrDefault(x => x.TreeAlias.InvariantEquals(appTree.TreeAlias)); if (found != null) { - dictionary[found.TreeAlias] = new SearchableApplicationTree(appTree.ApplicationAlias, appTree.Alias, found); + dictionary[found.TreeAlias] = new SearchableApplicationTree(appTree.ApplicationAlias, appTree.TreeAlias, found); } } return dictionary; diff --git a/src/Umbraco.Web/Services/IApplicationTreeService.cs b/src/Umbraco.Web/Services/IApplicationTreeService.cs deleted file mode 100644 index 1fd7bc939a..0000000000 --- a/src/Umbraco.Web/Services/IApplicationTreeService.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Web.Models.ContentEditing; - -namespace Umbraco.Web.Services -{ - public interface IApplicationTreeService - { - ///// - ///// Creates a new application tree. - ///// - ///// if set to true [initialize]. - ///// The sort order. - ///// The application alias. - ///// The alias. - ///// The title. - ///// The icon closed. - ///// The icon opened. - ///// The type. - //void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type); - - ///// - ///// Saves this instance. - ///// - //void SaveTree(ApplicationTree tree); - - ///// - ///// Deletes this instance. - ///// - //void DeleteTree(ApplicationTree tree); - - /// - /// Gets an ApplicationTree by it's tree alias. - /// - /// The tree alias. - /// An ApplicationTree instance - ApplicationTree GetByAlias(string treeAlias); - - /// - /// Gets all applicationTrees registered in umbraco from the umbracoAppTree table.. - /// - /// Returns a ApplicationTree Array - IEnumerable GetAll(); - - /// - /// Gets the application tree for the applcation with the specified alias - /// - /// The application alias. - /// Returns a ApplicationTree Array - IEnumerable GetApplicationTrees(string applicationAlias); - - ///// - ///// Gets the application tree for the applcation with the specified alias - ///// - ///// The application alias. - ///// - ///// Returns a ApplicationTree Array - //IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized); - - /// - /// Gets the grouped application trees for the application with the specified alias - /// - /// - /// - IDictionary> GetGroupedApplicationTrees(string applicationAlias); - } - - /// - /// Purely used to allow a service context to create the default services - /// - internal class EmptyApplicationTreeService : IApplicationTreeService - { - ///// - ///// Creates a new application tree. - ///// - ///// if set to true [initialize]. - ///// The sort order. - ///// The application alias. - ///// The alias. - ///// The title. - ///// The icon closed. - ///// The icon opened. - ///// The type. - //public void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) - //{ - // throw new System.NotImplementedException(); - //} - - ///// - ///// Saves this instance. - ///// - //public void SaveTree(ApplicationTree tree) - //{ - // throw new System.NotImplementedException(); - //} - - ///// - ///// Deletes this instance. - ///// - //public void DeleteTree(ApplicationTree tree) - //{ - // throw new System.NotImplementedException(); - //} - - /// - /// Gets an ApplicationTree by it's tree alias. - /// - /// The tree alias. - /// An ApplicationTree instance - public ApplicationTree GetByAlias(string treeAlias) - { - throw new System.NotImplementedException(); - } - - /// - /// Gets all applicationTrees registered in umbraco from the umbracoAppTree table.. - /// - /// Returns a ApplicationTree Array - public IEnumerable GetAll() - { - throw new System.NotImplementedException(); - } - - public IDictionary> GetGroupedApplicationTrees(string applicationAlias) - { - throw new System.NotImplementedException(); - } - - /// - /// Gets the application tree for the applcation with the specified alias - /// - /// The application alias. - /// Returns a ApplicationTree Array - public IEnumerable GetApplicationTrees(string applicationAlias) - { - throw new System.NotImplementedException(); - } - - /// - /// Gets the application tree for the applcation with the specified alias - /// - /// The application alias. - /// - /// Returns a ApplicationTree Array - public IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized) - { - throw new System.NotImplementedException(); - } - } -} diff --git a/src/Umbraco.Web/Services/ISectionService.cs b/src/Umbraco.Web/Services/ISectionService.cs index 560805634f..c325020cf1 100644 --- a/src/Umbraco.Web/Services/ISectionService.cs +++ b/src/Umbraco.Web/Services/ISectionService.cs @@ -25,92 +25,7 @@ namespace Umbraco.Web.Services /// The application alias. /// IBackOfficeSection GetByAlias(string appAlias); - - ///// - ///// Creates a new applcation if no application with the specified alias is found. - ///// - ///// The application name. - ///// The application alias. - ///// The application icon, which has to be located in umbraco/images/tray folder. - //void MakeNew(string name, string alias, string icon); - - ///// - ///// Makes the new. - ///// - ///// The name. - ///// The alias. - ///// The icon. - ///// The sort order. - //void MakeNew(string name, string alias, string icon, int sortOrder); - - ///// - ///// Deletes the section - ///// - //void DeleteSection(Section section); - } - - /// - /// Purely used to allow a service context to create the default services - /// - internal class EmptySectionService : ISectionService - { - /// - /// The cache storage for all applications - /// - public IEnumerable GetSections() - { - throw new System.NotImplementedException(); - } - - /// - /// Get the user's allowed sections - /// - /// - /// - public IEnumerable GetAllowedSections(int userId) - { - throw new System.NotImplementedException(); - } - - /// - /// Gets the application by its alias. - /// - /// The application alias. - /// - public IBackOfficeSection GetByAlias(string appAlias) - { - throw new System.NotImplementedException(); - } - - ///// - ///// Creates a new applcation if no application with the specified alias is found. - ///// - ///// The application name. - ///// The application alias. - ///// The application icon, which has to be located in umbraco/images/tray folder. - //public void MakeNew(string name, string alias, string icon) - //{ - // throw new System.NotImplementedException(); - //} - - ///// - ///// Makes the new. - ///// - ///// The name. - ///// The alias. - ///// The icon. - ///// The sort order. - //public void MakeNew(string name, string alias, string icon, int sortOrder) - //{ - // throw new System.NotImplementedException(); - //} - - ///// - ///// Deletes the section - ///// - //public void DeleteSection(IBackOfficeSection section) - //{ - // throw new System.NotImplementedException(); - //} + } + } diff --git a/src/Umbraco.Web/Services/ITreeService.cs b/src/Umbraco.Web/Services/ITreeService.cs new file mode 100644 index 0000000000..ce734cc5e4 --- /dev/null +++ b/src/Umbraco.Web/Services/ITreeService.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Trees; + +namespace Umbraco.Web.Services +{ + public interface ITreeService + { + /// + /// Gets an ApplicationTree by it's tree alias. + /// + /// The tree alias. + /// An ApplicationTree instance + ApplicationTree GetByAlias(string treeAlias); + + /// + /// Gets all applicationTrees registered in umbraco from the umbracoAppTree table.. + /// + /// Returns a ApplicationTree Array + IEnumerable GetAll(); + + /// + /// Gets the application tree for the applcation with the specified alias + /// + /// The application alias. + /// Returns a ApplicationTree Array + IEnumerable GetApplicationTrees(string applicationAlias); + + ///// + ///// Gets the application tree for the applcation with the specified alias + ///// + ///// The application alias. + ///// + ///// Returns a ApplicationTree Array + //IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized); + + /// + /// Gets the grouped application trees for the application with the specified alias + /// + /// + /// + IDictionary> GetGroupedApplicationTrees(string applicationAlias); + } + +} diff --git a/src/Umbraco.Web/Services/ApplicationTreeService.cs b/src/Umbraco.Web/Services/TreeService.cs similarity index 95% rename from src/Umbraco.Web/Services/ApplicationTreeService.cs rename to src/Umbraco.Web/Services/TreeService.cs index 72b26e26d3..cf010f1480 100644 --- a/src/Umbraco.Web/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Web/Services/TreeService.cs @@ -18,18 +18,18 @@ using Umbraco.Web.Trees; namespace Umbraco.Web.Services { - internal class ApplicationTreeService : IApplicationTreeService + internal class TreeService : ITreeService { private readonly ILogger _logger; private readonly TreeCollection _treeCollection; private static readonly object Locker = new object(); private readonly Lazy>> _groupedTrees; - public ApplicationTreeService(ILogger logger, TreeCollection treeCollection) + public TreeService(ILogger logger, TreeCollection treeCollection) { _logger = logger; _treeCollection = treeCollection; - //_groupedTrees = new Lazy>>(InitGroupedTrees); + _groupedTrees = new Lazy>>(InitGroupedTrees); } ///// @@ -233,7 +233,7 @@ namespace Umbraco.Web.Services //} /// - public ApplicationTree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.Alias == treeAlias); + public ApplicationTree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.TreeAlias == treeAlias); /// public IEnumerable GetAll() => _treeCollection; @@ -273,7 +273,7 @@ namespace Umbraco.Web.Services { foreach(var treeAliasInGroup in treeGroup) { - if (tree.Alias == treeAliasInGroup) + if (tree.TreeAlias == treeAliasInGroup) { if (resultGroup == null) resultGroup = new List(); resultGroup.Add(tree); @@ -286,21 +286,21 @@ namespace Umbraco.Web.Services return result; } - ///// - ///// Creates a group of all tree groups and their tree aliases - ///// - ///// - ///// - ///// Used to initialize the field - ///// - //private IReadOnlyCollection> InitGroupedTrees() - //{ - // var result = GetAll() - // .Select(x => (treeAlias: x.Alias, treeGroup: x.GetRuntimeType().GetCustomAttribute(false)?.TreeGroup)) - // .GroupBy(x => x.treeGroup, x => x.treeAlias) - // .ToList(); - // return result; - //} + /// + /// Creates a group of all tree groups and their tree aliases + /// + /// + /// + /// Used to initialize the field + /// + private IReadOnlyCollection> InitGroupedTrees() + { + var result = GetAll() + .Select(x => (treeAlias: x.TreeAlias, treeGroup: x.TreeControllerType.GetCustomAttribute(false)?.TreeGroup)) + .GroupBy(x => x.treeGroup, x => x.treeAlias) + .ToList(); + return result; + } ///// ///// Loads in the xml structure from disk if one is found, otherwise loads in an empty xml structure, calls the diff --git a/src/Umbraco.Web/Trees/ApplicationTree.cs b/src/Umbraco.Web/Trees/ApplicationTree.cs new file mode 100644 index 0000000000..5ed9847be3 --- /dev/null +++ b/src/Umbraco.Web/Trees/ApplicationTree.cs @@ -0,0 +1,69 @@ +using System; +using System.Diagnostics; +using Umbraco.Core.Services; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + [DebuggerDisplay("Tree - {TreeAlias} ({ApplicationAlias})")] + public class ApplicationTree : ITree + { + public ApplicationTree(int sortOrder, string applicationAlias, string alias, string title, Type treeControllerType, bool isSingleNodeTree) + { + SortOrder = sortOrder; + ApplicationAlias = applicationAlias; + TreeAlias = alias; + TreeTitle = title; + TreeControllerType = treeControllerType; + IsSingleNodeTree = isSingleNodeTree; + } + + /// + /// + /// Gets or sets the sort order. + /// + public int SortOrder { get; set; } + + /// + /// Gets the application alias. + /// + public string ApplicationAlias { get; set; } + + /// + public string TreeAlias { get; } + + /// + /// + /// Gets or sets the tree title (fallback if the tree alias isn't localized) + /// + /// The title. + public string TreeTitle { get; set; } + + public bool IsSingleNodeTree { get; } + + public Type TreeControllerType { get; } + + public static string GetRootNodeDisplayName(ITree tree, ILocalizedTextService textService) + { + var label = $"[{tree.TreeAlias}]"; + + // try to look up a the localized tree header matching the tree alias + var localizedLabel = textService.Localize("treeHeaders/" + tree.TreeAlias); + + // if the localizedLabel returns [alias] then return the title if it's defined + if (localizedLabel != null && localizedLabel.Equals(label, StringComparison.InvariantCultureIgnoreCase)) + { + if (string.IsNullOrEmpty(tree.TreeTitle) == false) + label = tree.TreeTitle; + } + else + { + // the localizedLabel translated into something that's not just [alias], so use the translation + label = localizedLabel; + } + + return label; + } + + } +} diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 7e7c77d607..0e405ca3f3 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -3,9 +3,13 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using System.Net.Http.Formatting; using System.Threading.Tasks; using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Routing; +using System.Web.Mvc; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; @@ -24,19 +28,20 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { + /// + /// Used to return tree root nodes + /// [AngularJsonOnlyConfiguration] [PluginController("UmbracoTrees")] public class ApplicationTreeController : UmbracoAuthorizedApiController { - private readonly TreeControllerResolver _treeControllerResolver; - private readonly IApplicationTreeService _treeService; + private readonly ITreeService _treeService; public ApplicationTreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, - IRuntimeState runtimeState, TreeControllerResolver treeControllerResolver, IApplicationTreeService treeService) + IRuntimeState runtimeState, ITreeService treeService) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { - _treeControllerResolver = treeControllerResolver; _treeService = treeService; } @@ -46,10 +51,9 @@ namespace Umbraco.Web.Trees /// The application to load tree for /// An optional single tree alias, if specified will only load the single tree for the request app /// - /// An optional bool (defaults to true), if set to false it will also load uninitialized trees /// [HttpQueryStringFilter("queryStrings")] - public async Task GetApplicationTrees(string application, string tree, FormDataCollection queryStrings/*, bool onlyInitialized = true*/) + public async Task GetApplicationTrees(string application, string tree, FormDataCollection queryStrings) { application = application.CleanForXss(); @@ -62,7 +66,7 @@ namespace Umbraco.Web.Trees if (string.IsNullOrEmpty(tree) == false || allTrees.Count == 1) { var apptree = !tree.IsNullOrWhiteSpace() - ? allTrees.FirstOrDefault(x => x.Alias == tree) + ? allTrees.FirstOrDefault(x => x.TreeAlias == tree) : allTrees.FirstOrDefault(); if (apptree == null) throw new HttpResponseException(HttpStatusCode.NotFound); @@ -153,15 +157,15 @@ namespace Umbraco.Web.Trees /// /// Get the root node for an application with multiple trees /// - /// + /// /// /// - private async Task GetRootForMultipleAppTree(ApplicationTree configTree, FormDataCollection queryStrings) + private async Task GetRootForMultipleAppTree(ApplicationTree tree, FormDataCollection queryStrings) { - if (configTree == null) throw new ArgumentNullException(nameof(configTree)); + if (tree == null) throw new ArgumentNullException(nameof(tree)); try { - var byControllerAttempt = await _treeControllerResolver.TryGetRootNodeFromControllerTree(configTree, queryStrings, ControllerContext); + var byControllerAttempt = await TryGetRootNodeFromControllerTree(tree, queryStrings, ControllerContext); if (byControllerAttempt.Success) { return byControllerAttempt.Result; @@ -174,54 +178,133 @@ namespace Umbraco.Web.Trees return null; } - throw new ApplicationException("Could not get root node for tree type " + configTree.Alias); + throw new ApplicationException("Could not get root node for tree type " + tree.TreeAlias); } /// /// Get the root node for an application with one tree /// - /// + /// /// /// /// /// - private async Task GetRootForSingleAppTree(ApplicationTree configTree, string id, FormDataCollection queryStrings, string application) + private async Task GetRootForSingleAppTree(ApplicationTree tree, string id, FormDataCollection queryStrings, string application) { var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture); - if (configTree == null) throw new ArgumentNullException(nameof(configTree)); - var byControllerAttempt = _treeControllerResolver.TryLoadFromControllerTree(configTree, id, queryStrings, ControllerContext); - if (byControllerAttempt.Success) + if (tree == null) throw new ArgumentNullException(nameof(tree)); + var byControllerAttempt = TryLoadFromControllerTree(tree, id, queryStrings, ControllerContext); + if (!byControllerAttempt.Success) + throw new ApplicationException("Could not render a tree for type " + tree.TreeAlias); + + var rootNode = await TryGetRootNodeFromControllerTree(tree, queryStrings, ControllerContext); + if (rootNode.Success == false) { - var rootNode = await _treeControllerResolver.TryGetRootNodeFromControllerTree(configTree, queryStrings, ControllerContext); - if (rootNode.Success == false) - { - //This should really never happen if we've successfully got the children above. - throw new InvalidOperationException("Could not create root node for tree " + configTree.Alias); - } - - var treeAttribute = _treeControllerResolver.GetTreeAttribute(configTree); - - var sectionRoot = TreeRootNode.CreateSingleTreeRoot( - rootId, - rootNode.Result.ChildNodesUrl, - rootNode.Result.MenuUrl, - rootNode.Result.Name, - byControllerAttempt.Result, - treeAttribute.IsSingleNodeTree); - - //assign the route path based on the root node, this means it will route there when the section is navigated to - //and no dashboards will be available for this section - sectionRoot.RoutePath = rootNode.Result.RoutePath; - - foreach (var d in rootNode.Result.AdditionalData) - { - sectionRoot.AdditionalData[d.Key] = d.Value; - } - return sectionRoot; - + //This should really never happen if we've successfully got the children above. + throw new InvalidOperationException("Could not create root node for tree " + tree.TreeAlias); } - throw new ApplicationException("Could not render a tree for type " + configTree.Alias); + var sectionRoot = TreeRootNode.CreateSingleTreeRoot( + rootId, + rootNode.Result.ChildNodesUrl, + rootNode.Result.MenuUrl, + rootNode.Result.Name, + byControllerAttempt.Result, + tree.IsSingleNodeTree); + + //assign the route path based on the root node, this means it will route there when the section is navigated to + //and no dashboards will be available for this section + sectionRoot.RoutePath = rootNode.Result.RoutePath; + + foreach (var d in rootNode.Result.AdditionalData) + { + sectionRoot.AdditionalData[d.Key] = d.Value; + } + return sectionRoot; + } + + /// + /// Proxies a request to the destination tree controller to get it's root tree node + /// + /// + /// + /// + /// + /// + /// This ensures that authorization filters are applied to the sub request + /// + private async Task> TryGetRootNodeFromControllerTree(ApplicationTree appTree, FormDataCollection formCollection, HttpControllerContext controllerContext) + { + //instantiate it, since we are proxying, we need to setup the instance with our current context + var instance = (TreeController)DependencyResolver.Current.GetService(appTree.TreeControllerType); + + //NOTE: This is all required in order to execute the auth-filters for the sub request, we + // need to "trick" web-api into thinking that it is actually executing the proxied controller. + + var urlHelper = controllerContext.Request.GetUrlHelper(); + //create the proxied URL for the controller action + var proxiedUrl = controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Authority) + + urlHelper.GetUmbracoApiService("GetRootNode", instance.GetType()); + //add the query strings to it + proxiedUrl += "?" + formCollection.ToQueryString(); + //create proxy route data specifying the action / controller to execute + var proxiedRouteData = new HttpRouteData( + controllerContext.RouteData.Route, + new HttpRouteValueDictionary(new { action = "GetRootNode", controller = ControllerExtensions.GetControllerName(instance.GetType()) })); + + //create a proxied controller context + var proxiedControllerContext = new HttpControllerContext( + controllerContext.Configuration, + proxiedRouteData, + new HttpRequestMessage(HttpMethod.Get, proxiedUrl)) + { + ControllerDescriptor = new HttpControllerDescriptor(controllerContext.ControllerDescriptor.Configuration, ControllerExtensions.GetControllerName(instance.GetType()), instance.GetType()), + RequestContext = controllerContext.RequestContext + }; + + instance.ControllerContext = proxiedControllerContext; + instance.Request = controllerContext.Request; + instance.RequestContext.RouteData = proxiedRouteData; + + //invoke auth filters for this sub request + var result = await instance.ControllerContext.InvokeAuthorizationFiltersForRequest(); + //if a result is returned it means they are unauthorized, just throw the response. + if (result != null) + { + throw new HttpResponseException(result); + } + + //return the root + var node = instance.GetRootNode(formCollection); + return node == null + ? Attempt.Fail(new InvalidOperationException("Could not return a root node for tree " + appTree.TreeAlias)) + : Attempt.Succeed(node); + } + + /// + /// Proxies a request to the destination tree controller to get it's tree node collection + /// + /// + /// + /// + /// + /// + private Attempt TryLoadFromControllerTree(ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext) + { + // instantiate it, since we are proxying, we need to setup the instance with our current context + var instance = (TreeController)DependencyResolver.Current.GetService(appTree.TreeControllerType); + if (instance == null) + throw new Exception("Failed to create tree " + appTree.TreeControllerType + "."); + + //TODO: Shouldn't we be applying the same proxying logic as above so that filters work? seems like an oversight + + instance.ControllerContext = controllerContext; + instance.Request = controllerContext.Request; + + // return its data + return Attempt.Succeed(instance.GetNodes(id, formCollection)); + } + } } diff --git a/src/Umbraco.Web/Trees/ITree.cs b/src/Umbraco.Web/Trees/ITree.cs new file mode 100644 index 0000000000..40be7338b0 --- /dev/null +++ b/src/Umbraco.Web/Trees/ITree.cs @@ -0,0 +1,31 @@ +namespace Umbraco.Web.Trees +{ + public interface ITree + { + /// + /// Gets or sets the sort order. + /// + /// The sort order. + int SortOrder { get; } + + /// + /// Gets the section alias. + /// + string ApplicationAlias { get; } + + /// + /// Gets the tree alias. + /// + string TreeAlias { get; } + + /// + /// Gets or sets the tree title (fallback if the tree alias isn't localized) + /// + string TreeTitle { get; } + + /// + /// Flag to define if this tree is a single node tree (will never contain child nodes, full screen app) + /// + bool IsSingleNodeTree { get; } + } +} diff --git a/src/Umbraco.Web/Trees/TreeAttribute.cs b/src/Umbraco.Web/Trees/TreeAttribute.cs index 1cf23c549f..dd63f8c172 100644 --- a/src/Umbraco.Web/Trees/TreeAttribute.cs +++ b/src/Umbraco.Web/Trees/TreeAttribute.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { @@ -6,15 +7,15 @@ namespace Umbraco.Web.Trees /// Identifies an application tree /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class TreeAttribute : Attribute + public class TreeAttribute : Attribute, ITree { /// /// Initializes a new instance of the class. /// /// The app alias. - /// The alias. + /// public TreeAttribute(string appAlias, - string alias) : this(appAlias, alias, null) + string treeAlias) : this(appAlias, treeAlias, null) { } @@ -22,16 +23,16 @@ namespace Umbraco.Web.Trees /// Initializes a new instance of the class. /// /// The app alias. - /// The alias. - /// The title. + /// + /// /// The icon closed. /// The icon open. /// if set to true [initialize]. /// The sort order. /// Flag to define if this tree is a single node tree (will never contain child nodes, full screen app) public TreeAttribute(string appAlias, - string alias, - string title, + string treeAlias, + string treeTitle, string iconClosed = "icon-folder", string iconOpen = "icon-folder-open", bool initialize = true, @@ -39,8 +40,8 @@ namespace Umbraco.Web.Trees bool isSingleNodeTree = false) { ApplicationAlias = appAlias; - Alias = alias; - Title = title; + TreeAlias = treeAlias; + TreeTitle = treeTitle; IconClosed = iconClosed; IconOpen = iconOpen; Initialize = initialize; @@ -48,17 +49,17 @@ namespace Umbraco.Web.Trees IsSingleNodeTree = isSingleNodeTree; } - public string ApplicationAlias { get; private set; } - public string Alias { get; private set; } - public string Title { get; private set; } - public string IconClosed { get; private set; } - public string IconOpen { get; private set; } - public bool Initialize { get; private set; } - public int SortOrder { get; private set; } + public string ApplicationAlias { get; } + public string TreeAlias { get; } + public string TreeTitle { get; } + public string IconClosed { get; } + public string IconOpen { get; } + public bool Initialize { get; } + public int SortOrder { get; } /// /// Flag to define if this tree is a single node tree (will never contain child nodes, full screen app) /// - public bool IsSingleNodeTree { get; private set; } + public bool IsSingleNodeTree { get; } } } diff --git a/src/Umbraco.Web/Trees/TreeCollection.cs b/src/Umbraco.Web/Trees/TreeCollection.cs index 8f913fb2d7..c7b60dea16 100644 --- a/src/Umbraco.Web/Trees/TreeCollection.cs +++ b/src/Umbraco.Web/Trees/TreeCollection.cs @@ -21,7 +21,26 @@ namespace Umbraco.Web.Trees { protected override TreeCollectionBuilder This => this; - //TODO: can we allow for re-ordering OOTB without exposing other methods? + private readonly List _instances = new List(); + + public void AddTree(ApplicationTree tree) + { + _instances.Add(tree); + } + + protected override IEnumerable CreateItems(IFactory factory) + { + return _instances; + + //var items = base.CreateItems(factory).ToList(); + //throw new NotImplementedException(); + ////validate the items, no actions should exist that do not either expose notifications or permissions + //var invalidItems = items.Where(x => !x.CanBePermissionAssigned && !x.ShowInNotifier).ToList(); + //if (invalidItems.Count == 0) return items; + + //var invalidActions = string.Join(", ", invalidItems.Select(x => "'" + x.Alias + "'")); + //throw new InvalidOperationException($"Invalid actions {invalidActions}'. All {typeof(IAction)} implementations must be true for either {nameof(IAction.CanBePermissionAssigned)} or {nameof(IAction.ShowInNotifier)}."); + } } } diff --git a/src/Umbraco.Web/Trees/TreeController.cs b/src/Umbraco.Web/Trees/TreeController.cs index 102671ec29..63e8f5aad5 100644 --- a/src/Umbraco.Web/Trees/TreeController.cs +++ b/src/Umbraco.Web/Trees/TreeController.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Concurrent; +using System.Linq; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; @@ -14,10 +16,10 @@ namespace Umbraco.Web.Trees public abstract class TreeController : TreeControllerBase { private TreeAttribute _attribute; - private string _rootNodeDisplayName; protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, applicationCache, logger, runtimeState) { + Initialize(); } protected TreeController() @@ -25,29 +27,42 @@ namespace Umbraco.Web.Trees Initialize(); } - /// - /// The name to display on the root node - /// - public override string RootNodeDisplayName - { - get - { - throw new NotImplementedException(); - //return _rootNodeDisplayName - // ?? (_rootNodeDisplayName = Services.ApplicationTreeService.GetByAlias(_attribute.Alias) - // ?.GetRootNodeDisplayName(Services.TextService)); - } - } + /// + public override string RootNodeDisplayName => ApplicationTree.GetRootNodeDisplayName(this, Services.TextService); - /// - /// Gets the current tree alias from the attribute assigned to it. - /// - public override string TreeAlias => _attribute.Alias; + /// + public override string TreeAlias => _attribute.TreeAlias; + /// + public override string TreeTitle => _attribute.TreeTitle; + /// + public override string ApplicationAlias => _attribute.ApplicationAlias; + /// + public override int SortOrder => _attribute.SortOrder; + /// + public override bool IsSingleNodeTree => _attribute.IsSingleNodeTree; private void Initialize() { - throw new NotImplementedException(); - //_attribute = GetType().GetTreeAttribute(); + _attribute = GetTreeAttribute(); + } + + private static readonly ConcurrentDictionary TreeAttributeCache = new ConcurrentDictionary(); + + private TreeAttribute GetTreeAttribute() + { + return TreeAttributeCache.GetOrAdd(GetType(), type => + { + //Locate the tree attribute + var treeAttributes = type + .GetCustomAttributes(false) + .ToArray(); + + if (treeAttributes.Length == 0) + throw new InvalidOperationException("The Tree controller is missing the " + typeof(TreeAttribute).FullName + " attribute"); + + //assign the properties of this object to those of the metadata attribute + return treeAttributes[0]; + }); } } } diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs index c00d6053c8..7a027033fc 100644 --- a/src/Umbraco.Web/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Trees /// Developers should generally inherit from TreeController. /// [AngularJsonOnlyConfiguration] - public abstract class TreeControllerBase : UmbracoAuthorizedApiController + public abstract class TreeControllerBase : UmbracoAuthorizedApiController, ITree { protected TreeControllerBase() { @@ -62,10 +62,16 @@ namespace Umbraco.Web.Trees /// public abstract string RootNodeDisplayName { get; } - /// - /// Gets the current tree alias from the attribute assigned to it. - /// + /// public abstract string TreeAlias { get; } + /// + public abstract string TreeTitle { get; } + /// + public abstract string ApplicationAlias { get; } + /// + public abstract int SortOrder { get; } + /// + public abstract bool IsSingleNodeTree { get; } /// /// Returns the root node for the tree diff --git a/src/Umbraco.Web/Trees/TreeControllerResolver.cs b/src/Umbraco.Web/Trees/TreeControllerResolver.cs deleted file mode 100644 index 62cafbb5dd..0000000000 --- a/src/Umbraco.Web/Trees/TreeControllerResolver.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Management.Instrumentation; -using System.Net.Http; -using System.Net.Http.Formatting; -using System.Threading.Tasks; -using System.Web.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Routing; -using System.Web.Mvc; -using Umbraco.Core; -using Umbraco.Web.Models.Trees; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Core.Composing; -using ApplicationTree = Umbraco.Web.Models.ContentEditing.ApplicationTree; - -namespace Umbraco.Web.Trees -{ - public class TreeControllerResolver - { - private readonly TreeCollection _trees; - private readonly UmbracoApiControllerTypeCollection _apiControllers; - - public TreeControllerResolver(TreeCollection trees, UmbracoApiControllerTypeCollection apiControllers) - { - _trees = trees; - _apiControllers = apiControllers; - } - - private static readonly ConcurrentDictionary TreeAttributeCache = new ConcurrentDictionary(); - private static readonly ConcurrentDictionary ResolvedControllerTypes = new ConcurrentDictionary(); - - private TreeAttribute GetTreeAttribute(Type treeControllerType) - { - return TreeAttributeCache.GetOrAdd(treeControllerType, type => - { - //Locate the tree attribute - var treeAttributes = type - .GetCustomAttributes(false) - .ToArray(); - - if (treeAttributes.Length == 0) - { - throw new InvalidOperationException("The Tree controller is missing the " + typeof(TreeAttribute).FullName + " attribute"); - } - - //assign the properties of this object to those of the metadata attribute - return treeAttributes[0]; - }); - } - - internal TreeAttribute GetTreeAttribute(ApplicationTree tree) - { - throw new NotImplementedException(); - //return ResolvedControllerTypes.GetOrAdd(tree.Alias, s => - //{ - // var controllerType = _apiControllers - // .OfType() - // .FirstOrDefault(x => x.) - //}); - - //return GetTreeAttribute(tree.GetRuntimeType()); - } - - private Type GetControllerType(ApplicationTree tree) - { - throw new NotImplementedException(); - } - - - internal Attempt TryGetControllerTree(ApplicationTree appTree) - { - throw new NotImplementedException(); - - ////get reference to all TreeApiControllers - //var controllerTrees = _apiControllers - // .Where(TypeHelper.IsTypeAssignableFrom) - // .ToArray(); - - ////find the one we're looking for - //var foundControllerTree = controllerTrees.FirstOrDefault(x => x == appTree.GetRuntimeType()); - //if (foundControllerTree == null) - //{ - // return Attempt.Fail(new InstanceNotFoundException("Could not find tree of type " + appTree.Type + " in any loaded DLLs")); - //} - //return Attempt.Succeed(foundControllerTree); - } - - /// - /// This will go and get the root node from a controller tree by executing the tree's GetRootNode method - /// - /// - /// - /// - /// - /// - /// This ensures that authorization filters are applied to the sub request - /// - internal async Task> TryGetRootNodeFromControllerTree(ApplicationTree appTree, FormDataCollection formCollection, HttpControllerContext controllerContext) - { - var foundControllerTreeAttempt = TryGetControllerTree(appTree); - if (foundControllerTreeAttempt.Success == false) - { - return Attempt.Fail(foundControllerTreeAttempt.Exception); - } - - var foundControllerTree = foundControllerTreeAttempt.Result; - //instantiate it, since we are proxying, we need to setup the instance with our current context - var instance = (TreeController)DependencyResolver.Current.GetService(foundControllerTree); - - //NOTE: This is all required in order to execute the auth-filters for the sub request, we - // need to "trick" web-api into thinking that it is actually executing the proxied controller. - - var urlHelper = controllerContext.Request.GetUrlHelper(); - //create the proxied URL for the controller action - var proxiedUrl = controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Authority) + - urlHelper.GetUmbracoApiService("GetRootNode", instance.GetType()); - //add the query strings to it - proxiedUrl += "?" + formCollection.ToQueryString(); - //create proxy route data specifying the action / controller to execute - var proxiedRouteData = new HttpRouteData( - controllerContext.RouteData.Route, - new HttpRouteValueDictionary(new {action = "GetRootNode", controller = ControllerExtensions.GetControllerName(instance.GetType())})); - - //create a proxied controller context - var proxiedControllerContext = new HttpControllerContext( - controllerContext.Configuration, - proxiedRouteData, - new HttpRequestMessage(HttpMethod.Get, proxiedUrl)) - { - ControllerDescriptor = new HttpControllerDescriptor(controllerContext.ControllerDescriptor.Configuration, ControllerExtensions.GetControllerName(instance.GetType()), instance.GetType()) - }; - - if (WebApiVersionCheck.WebApiVersion >= Version.Parse("5.0.0")) - { - //fixme - will this 'just' work now? - proxiedControllerContext.RequestContext = controllerContext.RequestContext; - - ////In WebApi2, this is required to be set: - //// proxiedControllerContext.RequestContext = controllerContext.RequestContext - //// but we need to do this with reflection because of codebase changes between version 4/5 - ////NOTE: Use TypeHelper here since the reflection is cached - //var controllerContextRequestContext = TypeHelper.GetProperty(controllerContext.GetType(), "RequestContext").GetValue(controllerContext); - //TypeHelper.GetProperty(proxiedControllerContext.GetType(), "RequestContext").SetValue(proxiedControllerContext, controllerContextRequestContext); - } - - instance.ControllerContext = proxiedControllerContext; - instance.Request = controllerContext.Request; - - if (WebApiVersionCheck.WebApiVersion >= Version.Parse("5.0.0")) - { - - //fixme - will this 'just' work now? - instance.RequestContext.RouteData = proxiedRouteData; - - ////now we can change the request context's route data to be the proxied route data - NOTE: we cannot do this directly above - //// because it will detect that the request context is different throw an exception. This is a change in webapi2 and we need to set - //// this with reflection due to codebase changes between version 4/5 - //// instance.RequestContext.RouteData = proxiedRouteData; - ////NOTE: Use TypeHelper here since the reflection is cached - //var instanceRequestContext = TypeHelper.GetProperty(typeof(ApiController), "RequestContext").GetValue(instance); - //TypeHelper.GetProperty(instanceRequestContext.GetType(), "RouteData").SetValue(instanceRequestContext, proxiedRouteData); - } - - //invoke auth filters for this sub request - var result = await instance.ControllerContext.InvokeAuthorizationFiltersForRequest(); - //if a result is returned it means they are unauthorized, just throw the response. - if (result != null) - { - throw new HttpResponseException(result); - } - - //return the root - var node = instance.GetRootNode(formCollection); - return node == null - ? Attempt.Fail(new InvalidOperationException("Could not return a root node for tree " + appTree.Alias)) - : Attempt.Succeed(node); - } - - internal Attempt TryLoadFromControllerTree(ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext) - { - var foundControllerTreeAttempt = TryGetControllerTree(appTree); - if (foundControllerTreeAttempt.Success == false) - return Attempt.Fail(foundControllerTreeAttempt.Exception); - - // instantiate it, since we are proxying, we need to setup the instance with our current context - var foundControllerTree = foundControllerTreeAttempt.Result; - var instance = (TreeController) DependencyResolver.Current.GetService(foundControllerTree); - if (instance == null) - throw new Exception("Failed to get tree " + foundControllerTree.FullName + "."); - - instance.ControllerContext = controllerContext; - instance.Request = controllerContext.Request; - - // return its data - return Attempt.Succeed(instance.GetNodes(id, formCollection)); - } - - } - -} diff --git a/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs b/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs deleted file mode 100644 index 5473fee7bb..0000000000 --- a/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Linq; -using System.Net.Http.Formatting; -using Umbraco.Core; -using Umbraco.Web.Models.Trees; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi.Filters; - -using Constants = Umbraco.Core.Constants; - -namespace Umbraco.Web.Trees -{ - [UmbracoTreeAuthorize(Constants.Trees.UserPermissions)] - [Tree(Constants.Applications.Users, Constants.Trees.UserPermissions, null, sortOrder: 2)] - [PluginController("UmbracoTrees")] - [CoreTree] - public class UserPermissionsTreeController : TreeController - { - protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) - { - var nodes = new TreeNodeCollection(); - long totalUsers; - nodes.AddRange( - Services.UserService.GetAll(0, int.MaxValue, out totalUsers) - .Where(x => x.Id != Constants.Security.SuperUserId && x.IsApproved) - .Select(x => CreateTreeNode(x.Id.ToString(), - id, - queryStrings, - x.Name, - "icon-user", - false, - "/" + queryStrings.GetValue("application") + "/framed/" - + Uri.EscapeDataString("users/PermissionEditor.aspx?id=" + x.Id)))); - - return nodes; - } - - protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) - { - var menu = new MenuItemCollection(); - - if (id == Constants.System.Root.ToInvariantString()) - { - // root actions - menu.Items.Add(new RefreshNode(Services.TextService, true)); - return menu; - } - - return menu; - } - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f1d15e9ea6..0b1603c9e3 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -166,8 +166,9 @@ - + + @@ -183,7 +184,7 @@ - + @@ -551,7 +552,6 @@ - @@ -649,7 +649,7 @@ - + @@ -972,7 +972,6 @@ - @@ -1056,7 +1055,6 @@ - diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs index cc483db416..5ad3da7f4d 100644 --- a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs @@ -41,18 +41,16 @@ namespace Umbraco.Web.WebApi.Filters return true; } - throw new NotImplementedException(); + var apps = _treeAliases.Select(x => Current.TreeService + .GetByAlias(x)) + .WhereNotNull() + .Select(x => x.ApplicationAlias) + .Distinct() + .ToArray(); - //var apps = _treeAliases.Select(x => Current.Services.ApplicationTreeService - // .GetByAlias(x)) - // .WhereNotNull() - // .Select(x => x.ApplicationAlias) - // .Distinct() - // .ToArray(); - - //return Current.UmbracoContext.Security.CurrentUser != null - // && apps.Any(app => Current.UmbracoContext.Security.UserHasSectionAccess( - // app, Current.UmbracoContext.Security.CurrentUser)); + return Current.UmbracoContext.Security.CurrentUser != null + && apps.Any(app => Current.UmbracoContext.Security.UserHasSectionAccess( + app, Current.UmbracoContext.Security.CurrentUser)); } } } diff --git a/src/Umbraco.Web/WebApi/MvcVersionCheck.cs b/src/Umbraco.Web/WebApi/MvcVersionCheck.cs deleted file mode 100644 index 3c84fa91ce..0000000000 --- a/src/Umbraco.Web/WebApi/MvcVersionCheck.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Umbraco.Web.WebApi -{ - internal class WebApiVersionCheck - { - public static System.Version WebApiVersion - { - get { return typeof(System.Web.Http.ApiController).Assembly.GetName().Version; } - } - } -} diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs index d84ab3fe4a..cdb1aa2f51 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerTypeCollection.cs @@ -8,8 +8,6 @@ namespace Umbraco.Web.WebApi // which we are not doing at the moment // we can inherit from BuilderCollectionBase and just be enumerable - //fixme: this should be LazyCollectionBuilderBase ? - public class UmbracoApiControllerTypeCollection : BuilderCollectionBase { public UmbracoApiControllerTypeCollection(IEnumerable items) From 0160f141f4104c1048cf96f498b2dc1cc4a20e06 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:04:53 +1100 Subject: [PATCH 146/223] cleanup and explicitly registering sections --- .../Services/SectionServiceTests.cs | 2 +- .../TreesAndSections/ApplicationTreeTest.cs | 397 ----------------- .../ResourceFiles.Designer.cs | 91 ---- .../TreesAndSections/ResourceFiles.resx | 127 ------ .../TreesAndSections/SectionTests.cs | 252 ----------- .../TreesAndSections/applications.config | 16 - .../TreesAndSections/trees.config | 8 - src/Umbraco.Tests/Umbraco.Tests.csproj | 13 - .../Cache/ApplicationTreeCacheRefresher.cs | 46 -- .../Cache/DistributedCacheBinder_Handlers.cs | 47 -- .../Cache/DistributedCacheExtensions.cs | 19 - .../ContentEditing/IBackOfficeSection.cs | 15 - .../Models/Mapping/SectionMapperProfile.cs | 1 + .../Models/Trees/ApplicationDefinitions.cs | 77 ---- .../Models/Trees/IBackOfficeSection.cs | 12 + .../{SectionRootNode.cs => TreeRootNode.cs} | 0 src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 11 +- src/Umbraco.Web/Services/ISectionService.cs | 1 + src/Umbraco.Web/Services/ITreeService.cs | 10 +- src/Umbraco.Web/Services/SectionService.cs | 253 +---------- src/Umbraco.Web/Services/TreeService.cs | 410 +----------------- .../Trees/BackOfficeSectionCollection.cs | 8 +- .../BackOfficeSectionCollectionBuilder.cs | 10 + .../Trees/ContentBackOfficeSection.cs | 15 + src/Umbraco.Web/Trees/ITree.cs | 1 + .../Trees/MediaBackOfficeSection.cs | 15 + .../Trees/MembersBackOfficeSection.cs | 15 + .../Trees/PackagesBackOfficeSection.cs | 15 + .../Trees/SettingsBackOfficeSection.cs | 15 + .../Trees/TranslationBackOfficeSection.cs | 15 + src/Umbraco.Web/Trees/TreeCollection.cs | 27 -- .../Trees/TreeCollectionBuilder.cs | 18 + .../Trees/UsersBackOfficeSection.cs | 15 + src/Umbraco.Web/Umbraco.Web.csproj | 15 +- 34 files changed, 183 insertions(+), 1809 deletions(-) delete mode 100644 src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs delete mode 100644 src/Umbraco.Tests/TreesAndSections/ResourceFiles.Designer.cs delete mode 100644 src/Umbraco.Tests/TreesAndSections/ResourceFiles.resx delete mode 100644 src/Umbraco.Tests/TreesAndSections/SectionTests.cs delete mode 100644 src/Umbraco.Tests/TreesAndSections/applications.config delete mode 100644 src/Umbraco.Tests/TreesAndSections/trees.config delete mode 100644 src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs delete mode 100644 src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs delete mode 100644 src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs create mode 100644 src/Umbraco.Web/Models/Trees/IBackOfficeSection.cs rename src/Umbraco.Web/Models/Trees/{SectionRootNode.cs => TreeRootNode.cs} (100%) create mode 100644 src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs create mode 100644 src/Umbraco.Web/Trees/ContentBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/MediaBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/MembersBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/PackagesBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/SettingsBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/TranslationBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/TreeCollectionBuilder.cs create mode 100644 src/Umbraco.Web/Trees/UsersBackOfficeSection.cs diff --git a/src/Umbraco.Tests/Services/SectionServiceTests.cs b/src/Umbraco.Tests/Services/SectionServiceTests.cs index 206c99ffbf..9211755251 100644 --- a/src/Umbraco.Tests/Services/SectionServiceTests.cs +++ b/src/Umbraco.Tests/Services/SectionServiceTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.Services public class SectionServiceTests : TestWithSomeContentBase { //fixme - private ISectionService SectionService => new SectionService(ServiceContext.UserService, null, null); + private ISectionService SectionService => new SectionService(ServiceContext.UserService, null); [Test] diff --git a/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs b/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs deleted file mode 100644 index 95d90f1463..0000000000 --- a/src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs +++ /dev/null @@ -1,397 +0,0 @@ -//using System.IO; -//using NUnit.Framework; -//using Umbraco.Core.Services; -//using Umbraco.Tests.TestHelpers; -//using System; -//using System.Linq; -//using System.Threading; -//using Umbraco.Tests.Testing; -//using Umbraco.Web.Services; -//using Current = Umbraco.Web.Composing.Current; - -//namespace Umbraco.Tests.TreesAndSections -//{ - - -// /// -// ///This is a test class for ApplicationTreeTest and is intended -// ///to contain all ApplicationTreeTest Unit Tests -// /// -// [TestFixture] -// [Apartment(ApartmentState.STA)] -// [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] -// public class ApplicationTreeTest : TestWithDatabaseBase -// { -// public override void SetUp() -// { -// base.SetUp(); - -// var treesConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/trees.config"); -// var appConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/applications.config"); -// Directory.CreateDirectory(TestHelper.MapPathForTest("~/TEMP/TreesAndSections")); -// using (var writer = File.CreateText(treesConfig)) -// { -// writer.Write(ResourceFiles.trees); -// } -// using (var writer = File.CreateText(appConfig)) -// { -// writer.Write(ResourceFiles.applications); -// } - -// //ApplicationTreeService.TreeConfigFilePath = treesConfig; -// SectionService.AppConfigFilePath = appConfig; -// } - -// public override void TearDown() -// { -// base.TearDown(); - -// if (Directory.Exists(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"))) -// { -// Directory.Delete(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"), true); -// } -// //ApplicationTreeService.TreeConfigFilePath = null; -// SectionService.AppConfigFilePath = null; -// } - -// ///// -// ///// Creates a new app tree linked to an application, then delete the application and make sure the tree is gone as well -// ///// -// //[Test()] -// //public void ApplicationTree_Make_New_Then_Delete_App() -// //{ -// // //create new app -// // var appName = Guid.NewGuid().ToString("N"); -// // var treeName = Guid.NewGuid().ToString("N"); -// // Current.Services.SectionService.MakeNew(appName, appName, "icon.jpg"); - -// // //check if it exists -// // var app = Current.Services.SectionService.GetByAlias(appName); -// // Assert.IsNotNull(app); - -// // //create the new app tree assigned to the new app -// // Current.Services.ApplicationTreeService.MakeNew(false, 0, app.Alias, treeName, treeName, "icon.jpg", "icon.jpg", "Umbraco.Web.Trees.ContentTreeController, Umbraco.Web"); -// // var tree = Current.Services.ApplicationTreeService.GetByAlias(treeName); -// // Assert.IsNotNull(tree); - -// // //now delete the app -// // Current.Services.SectionService.DeleteSection(app); - -// // //check that the tree is gone -// // Assert.AreEqual(0, Current.Services.ApplicationTreeService.GetApplicationTrees(treeName).Count()); -// //} - - -// #region Tests to write -// ///// -// /////A test for ApplicationTree Constructor -// ///// -// //[TestMethod()] -// //public void ApplicationTreeConstructorTest() -// //{ -// // bool silent = false; // TODO: Initialize to an appropriate value -// // bool initialize = false; // TODO: Initialize to an appropriate value -// // byte sortOrder = 0; // TODO: Initialize to an appropriate value -// // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value -// // string alias = string.Empty; // TODO: Initialize to an appropriate value -// // string title = string.Empty; // TODO: Initialize to an appropriate value -// // string iconClosed = string.Empty; // TODO: Initialize to an appropriate value -// // string iconOpened = string.Empty; // TODO: Initialize to an appropriate value -// // string assemblyName = string.Empty; // TODO: Initialize to an appropriate value -// // string type = string.Empty; // TODO: Initialize to an appropriate value -// // string action = string.Empty; // TODO: Initialize to an appropriate value -// // ApplicationTree target = new ApplicationTree(silent, initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, assemblyName, type, action); -// // Assert.Inconclusive("TODO: Implement code to verify target"); -// //} - -// ///// -// /////A test for ApplicationTree Constructor -// ///// -// //[TestMethod()] -// //public void ApplicationTreeConstructorTest1() -// //{ -// // ApplicationTree target = new ApplicationTree(); -// // Assert.Inconclusive("TODO: Implement code to verify target"); -// //} - -// ///// -// /////A test for Delete -// ///// -// //[TestMethod()] -// //public void DeleteTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // target.Delete(); -// // Assert.Inconclusive("A method that does not return a value cannot be verified."); -// //} - - -// ///// -// /////A test for Save -// ///// -// //[TestMethod()] -// //public void SaveTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // target.Save(); -// // Assert.Inconclusive("A method that does not return a value cannot be verified."); -// //} - -// ///// -// /////A test for getAll -// ///// -// //[TestMethod()] -// //public void getAllTest() -// //{ -// // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value -// // ApplicationTree[] actual; -// // actual = ApplicationTree.getAll(); -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for getApplicationTree -// ///// -// //[TestMethod()] -// //public void getApplicationTreeTest() -// //{ -// // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value -// // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value -// // ApplicationTree[] actual; -// // actual = ApplicationTree.getApplicationTree(applicationAlias); -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for getApplicationTree -// ///// -// //[TestMethod()] -// //public void getApplicationTreeTest1() -// //{ -// // string applicationAlias = string.Empty; // TODO: Initialize to an appropriate value -// // bool onlyInitializedApplications = false; // TODO: Initialize to an appropriate value -// // ApplicationTree[] expected = null; // TODO: Initialize to an appropriate value -// // ApplicationTree[] actual; -// // actual = ApplicationTree.getApplicationTree(applicationAlias, onlyInitializedApplications); -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for getByAlias -// ///// -// //[TestMethod()] -// //public void getByAliasTest() -// //{ -// // string treeAlias = string.Empty; // TODO: Initialize to an appropriate value -// // ApplicationTree expected = null; // TODO: Initialize to an appropriate value -// // ApplicationTree actual; -// // actual = ApplicationTree.getByAlias(treeAlias); -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for Action -// ///// -// //[TestMethod()] -// //public void ActionTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.Action = expected; -// // actual = target.Action; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for Alias -// ///// -// //[TestMethod()] -// //public void AliasTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string actual; -// // actual = target.Alias; -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for ApplicationAlias -// ///// -// //[TestMethod()] -// //public void ApplicationAliasTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string actual; -// // actual = target.ApplicationAlias; -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for AssemblyName -// ///// -// //[TestMethod()] -// //public void AssemblyNameTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.AssemblyName = expected; -// // actual = target.AssemblyName; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for IconClosed -// ///// -// //[TestMethod()] -// //public void IconClosedTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.IconClosed = expected; -// // actual = target.IconClosed; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for IconOpened -// ///// -// //[TestMethod()] -// //public void IconOpenedTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.IconOpened = expected; -// // actual = target.IconOpened; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for Initialize -// ///// -// //[TestMethod()] -// //public void InitializeTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // bool expected = false; // TODO: Initialize to an appropriate value -// // bool actual; -// // target.Initialize = expected; -// // actual = target.Initialize; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for Silent -// ///// -// //[TestMethod()] -// //public void SilentTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // bool expected = false; // TODO: Initialize to an appropriate value -// // bool actual; -// // target.Silent = expected; -// // actual = target.Silent; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for SortOrder -// ///// -// //[TestMethod()] -// //public void SortOrderTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // byte expected = 0; // TODO: Initialize to an appropriate value -// // byte actual; -// // target.SortOrder = expected; -// // actual = target.SortOrder; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for SqlHelper -// ///// -// //[TestMethod()] -// //public void SqlHelperTest() -// //{ -// // ISqlHelper actual; -// // actual = ApplicationTree.SqlHelper; -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for Title -// ///// -// //[TestMethod()] -// //public void TitleTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.Title = expected; -// // actual = target.Title; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for Type -// ///// -// //[TestMethod()] -// //public void TypeTest() -// //{ -// // ApplicationTree target = new ApplicationTree(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.Type = expected; -// // actual = target.Type; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} -// #endregion - -// #region Additional test attributes -// // -// //You can use the following additional attributes as you write your tests: -// // -// //Use ClassInitialize to run code before running the first test in the class -// //[ClassInitialize()] -// //public static void MyClassInitialize(TestContext testContext) -// //{ -// //} -// // -// //Use ClassCleanup to run code after all tests in a class have run -// //[ClassCleanup()] -// //public static void MyClassCleanup() -// //{ -// //} -// // -// //Use TestInitialize to run code before running each test -// //[TestInitialize()] -// //public void MyTestInitialize() -// //{ -// //} -// // -// //Use TestCleanup to run code after each test has run -// //[TestCleanup()] -// //public void MyTestCleanup() -// //{ -// //} -// // -// #endregion -// } -//} diff --git a/src/Umbraco.Tests/TreesAndSections/ResourceFiles.Designer.cs b/src/Umbraco.Tests/TreesAndSections/ResourceFiles.Designer.cs deleted file mode 100644 index 02bc84649e..0000000000 --- a/src/Umbraco.Tests/TreesAndSections/ResourceFiles.Designer.cs +++ /dev/null @@ -1,91 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Umbraco.Tests.TreesAndSections { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ResourceFiles { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ResourceFiles() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.TreesAndSections.ResourceFiles", typeof(ResourceFiles).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> - ///<applications> - /// <add alias="content" name="content" icon="file" sortOrder="0" /> - /// <add alias="0b486ac9c0f1456996192c6ed1f03e57" name="0b486ac9c0f1456996192c6ed1f03e57" icon="icon.jpg" sortOrder="1" /> - /// <add alias="1ffbc301744c4e75ae3054d741954c7b" name="1ffbc301744c4e75ae3054d741954c7b" icon="icon.jpg" sortOrder="2" /> - /// <add alias="1838c3e1591f4008bbafe59a06a00a31" name="1838c3e1591f4008bbafe59a06a00a31" icon="icon.jpg" sortOrder="3" /> - /// <add alias="e5badae2 [rest of string was truncated]";. - /// - internal static string applications { - get { - return ResourceManager.GetString("applications", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> - ///<trees> - /// <add initialize="false" sortOrder="0" alias="1838c3e1591f4008bbafe59a06a00a31" application="1838c3e1591f4008bbafe59a06a00a31" title="1838c3e1591f4008bbafe59a06a00a31" iconClosed="icon.jpg" iconOpen="icon.jpg" type="nulltype" /> - /// <add initialize="false" sortOrder="0" alias="e5badae2fc5e4cd7acb3700320e33b8b" application="e5badae2fc5e4cd7acb3700320e33b8b" title="e5badae2fc5e4cd7acb3700320e33b8b" iconClosed="icon.jpg" iconOpen="icon.jpg" type="nulltype" /> - /// [rest of string was truncated]";. - /// - internal static string trees { - get { - return ResourceManager.GetString("trees", resourceCulture); - } - } - } -} diff --git a/src/Umbraco.Tests/TreesAndSections/ResourceFiles.resx b/src/Umbraco.Tests/TreesAndSections/ResourceFiles.resx deleted file mode 100644 index fac58dc842..0000000000 --- a/src/Umbraco.Tests/TreesAndSections/ResourceFiles.resx +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - applications.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - trees.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - \ No newline at end of file diff --git a/src/Umbraco.Tests/TreesAndSections/SectionTests.cs b/src/Umbraco.Tests/TreesAndSections/SectionTests.cs deleted file mode 100644 index 83de6c4479..0000000000 --- a/src/Umbraco.Tests/TreesAndSections/SectionTests.cs +++ /dev/null @@ -1,252 +0,0 @@ -//using System.IO; -//using NUnit.Framework; -//using Umbraco.Core.Services; -//using Umbraco.Tests.TestHelpers; -//using System; -//using Umbraco.Core.Composing; -//using Umbraco.Tests.Testing; -//using Umbraco.Web.Services; - -//namespace Umbraco.Tests.TreesAndSections -//{ -// /// -// ///This is a test class for ApplicationTest and is intended -// ///to contain all ApplicationTest Unit Tests -// /// -// [TestFixture] -// [UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] -// public class SectionTests : TestWithDatabaseBase -// { -// protected override void Compose() -// { -// base.Compose(); -// Composition.RegisterUnique(); -// } - -// public override void SetUp() -// { -// base.SetUp(); - -// var treesConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/trees.config"); -// var appConfig = TestHelper.MapPathForTest("~/TEMP/TreesAndSections/applications.config"); -// Directory.CreateDirectory(TestHelper.MapPathForTest("~/TEMP/TreesAndSections")); -// using (var writer = File.CreateText(treesConfig)) -// { -// writer.Write(ResourceFiles.trees); -// } -// using (var writer = File.CreateText(appConfig)) -// { -// writer.Write(ResourceFiles.applications); -// } - -// ApplicationTreeService.TreeConfigFilePath = treesConfig; -// SectionService.AppConfigFilePath = appConfig; -// } - -// public override void TearDown() -// { -// base.TearDown(); - -// if (Directory.Exists(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"))) -// { -// Directory.Delete(TestHelper.MapPathForTest("~/TEMP/TreesAndSections"), true); -// } -// ApplicationTreeService.TreeConfigFilePath = null; -// SectionService.AppConfigFilePath = null; -// } - -// ///// -// ///// Create a new application and delete it -// ///// -// //[Test()] -// //public void Application_Make_New() -// //{ -// // var name = Guid.NewGuid().ToString("N"); -// // ServiceContext.SectionService.MakeNew(name, name, "icon.jpg"); - -// // //check if it exists -// // var app = ServiceContext.SectionService.GetByAlias(name); -// // Assert.IsNotNull(app); - -// // //now remove it -// // ServiceContext.SectionService.DeleteSection(app); -// // Assert.IsNull(ServiceContext.SectionService.GetByAlias(name)); -// //} - -// #region Tests to write - - -// ///// -// /////A test for Application Constructor -// ///// -// //[TestMethod()] -// //public void ApplicationConstructorTest() -// //{ -// // string name = string.Empty; // TODO: Initialize to an appropriate value -// // string alias = string.Empty; // TODO: Initialize to an appropriate value -// // string icon = string.Empty; // TODO: Initialize to an appropriate value -// // Application target = new Application(name, alias, icon); -// // Assert.Inconclusive("TODO: Implement code to verify target"); -// //} - -// ///// -// /////A test for Application Constructor -// ///// -// //[TestMethod()] -// //public void ApplicationConstructorTest1() -// //{ -// // Application target = new Application(); -// // Assert.Inconclusive("TODO: Implement code to verify target"); -// //} - -// ///// -// /////A test for Delete -// ///// -// //[TestMethod()] -// //public void DeleteTest() -// //{ -// // Application target = new Application(); // TODO: Initialize to an appropriate value -// // target.Delete(); -// // Assert.Inconclusive("A method that does not return a value cannot be verified."); -// //} - - - -// ///// -// /////A test for MakeNew -// ///// -// //[TestMethod()] -// //public void MakeNewTest1() -// //{ -// // string name = string.Empty; // TODO: Initialize to an appropriate value -// // string alias = string.Empty; // TODO: Initialize to an appropriate value -// // string icon = string.Empty; // TODO: Initialize to an appropriate value -// // Application.MakeNew(name, alias, icon); -// // Assert.Inconclusive("A method that does not return a value cannot be verified."); -// //} - -// ///// -// /////A test for RegisterIApplications -// ///// -// //[TestMethod()] -// //public void RegisterIApplicationsTest() -// //{ -// // Application.RegisterIApplications(); -// // Assert.Inconclusive("A method that does not return a value cannot be verified."); -// //} - -// ///// -// /////A test for getAll -// ///// -// //[TestMethod()] -// //public void getAllTest() -// //{ -// // List expected = null; // TODO: Initialize to an appropriate value -// // List actual; -// // actual = Application.getAll(); -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for getByAlias -// ///// -// //[TestMethod()] -// //public void getByAliasTest() -// //{ -// // string appAlias = string.Empty; // TODO: Initialize to an appropriate value -// // Application expected = null; // TODO: Initialize to an appropriate value -// // Application actual; -// // actual = Application.getByAlias(appAlias); -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for SqlHelper -// ///// -// //[TestMethod()] -// //public void SqlHelperTest() -// //{ -// // ISqlHelper actual; -// // actual = Application.SqlHelper; -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for alias -// ///// -// //[TestMethod()] -// //public void aliasTest() -// //{ -// // Application target = new Application(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.alias = expected; -// // actual = target.alias; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for icon -// ///// -// //[TestMethod()] -// //public void iconTest() -// //{ -// // Application target = new Application(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.icon = expected; -// // actual = target.icon; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} - -// ///// -// /////A test for name -// ///// -// //[TestMethod()] -// //public void nameTest() -// //{ -// // Application target = new Application(); // TODO: Initialize to an appropriate value -// // string expected = string.Empty; // TODO: Initialize to an appropriate value -// // string actual; -// // target.name = expected; -// // actual = target.name; -// // Assert.AreEqual(expected, actual); -// // Assert.Inconclusive("Verify the correctness of this test method."); -// //} -// #endregion - -// #region Additional test attributes -// // -// //You can use the following additional attributes as you write your tests: -// // -// //Use ClassInitialize to run code before running the first test in the class -// //[ClassInitialize()] -// //public static void MyClassInitialize(TestContext testContext) -// //{ -// //} -// // -// //Use ClassCleanup to run code after all tests in a class have run -// //[ClassCleanup()] -// //public static void MyClassCleanup() -// //{ -// //} -// // -// //Use TestInitialize to run code before running each test -// //[TestInitialize()] -// //public void MyTestInitialize() -// //{ -// //} -// // -// //Use TestCleanup to run code after each test has run -// //[TestCleanup()] -// //public void MyTestCleanup() -// //{ -// //} -// // -// #endregion -// } -//} diff --git a/src/Umbraco.Tests/TreesAndSections/applications.config b/src/Umbraco.Tests/TreesAndSections/applications.config deleted file mode 100644 index aadd1c5407..0000000000 --- a/src/Umbraco.Tests/TreesAndSections/applications.config +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Umbraco.Tests/TreesAndSections/trees.config b/src/Umbraco.Tests/TreesAndSections/trees.config deleted file mode 100644 index d21fea28a9..0000000000 --- a/src/Umbraco.Tests/TreesAndSections/trees.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e49ba250fa..408b0f96ca 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -423,13 +423,6 @@ - - True - True - ResourceFiles.resx - - - @@ -525,8 +518,6 @@ Designer Always - - Designer @@ -561,10 +552,6 @@ ImportResources.Designer.cs Designer - - ResXFileCodeGenerator - ResourceFiles.Designer.cs - ResXFileCodeGenerator TestFiles.Designer.cs diff --git a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs deleted file mode 100644 index 4d6740a0b1..0000000000 --- a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs +++ /dev/null @@ -1,46 +0,0 @@ -//using System; -//using Umbraco.Core.Cache; - -//namespace Umbraco.Web.Cache -//{ -// public sealed class ApplicationTreeCacheRefresher : CacheRefresherBase -// { -// public ApplicationTreeCacheRefresher(CacheHelper cacheHelper) -// : base(cacheHelper) -// { } - -// #region Define - -// protected override ApplicationTreeCacheRefresher This => this; - -// public static readonly Guid UniqueId = Guid.Parse("0AC6C028-9860-4EA4-958D-14D39F45886E"); - -// public override Guid RefresherUniqueId => UniqueId; - -// public override string Name => "Application Tree Cache Refresher"; - -// #endregion - -// #region Refresher - -// public override void RefreshAll() -// { -// CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); -// base.RefreshAll(); -// } - -// public override void Refresh(int id) -// { -// Remove(id); -// base.Refresh(id); -// } - -// public override void Remove(int id) -// { -// CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); -// base.Remove(id); -// } - -// #endregion -// } -//} diff --git a/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs b/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs index 421eb546a4..3a3eb1b8fb 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs @@ -46,20 +46,6 @@ namespace Umbraco.Web.Cache _logger.Info("Initializing Umbraco internal event handlers for cache refreshing."); - //// bind to application tree events - //Bind(() => ApplicationTreeService.Deleted += ApplicationTreeService_Deleted, - // () => ApplicationTreeService.Deleted -= ApplicationTreeService_Deleted); - //Bind(() => ApplicationTreeService.Updated += ApplicationTreeService_Updated, - // () => ApplicationTreeService.Updated -= ApplicationTreeService_Updated); - //Bind(() => ApplicationTreeService.New += ApplicationTreeService_New, - // () => ApplicationTreeService.New -= ApplicationTreeService_New); - - //// bind to application events - //Bind(() => SectionService.Deleted += SectionService_Deleted, - // () => SectionService.Deleted -= SectionService_Deleted); - //Bind(() => SectionService.New += SectionService_New, - // () => SectionService.New -= SectionService_New); - // bind to user and user group events Bind(() => UserService.SavedUserGroup += UserService_SavedUserGroup, () => UserService.SavedUserGroup -= UserService_SavedUserGroup); @@ -231,39 +217,6 @@ namespace Umbraco.Web.Cache #endregion - //#region ApplicationTreeService - - //private void ApplicationTreeService_New(ApplicationTree sender, EventArgs e) - //{ - // _distributedCache.RefreshAllApplicationTreeCache(); - //} - - //private void ApplicationTreeService_Updated(ApplicationTree sender, EventArgs e) - //{ - // _distributedCache.RefreshAllApplicationTreeCache(); - //} - - //private void ApplicationTreeService_Deleted(ApplicationTree sender, EventArgs e) - //{ - // _distributedCache.RefreshAllApplicationTreeCache(); - //} - - //#endregion - - //#region Application event handlers - - //private void SectionService_New(ISectionService sender, EventArgs e) - //{ - // _distributedCache.RefreshAllApplicationCache(); - //} - - //private void SectionService_Deleted(ISectionService sender, EventArgs e) - //{ - // _distributedCache.RefreshAllApplicationCache(); - //} - - //#endregion - #region LocalizationService / Dictionary private void LocalizationService_SavedDictionaryItem(ILocalizationService sender, SaveEventArgs e) diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index aab0f9b157..80c49e279c 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -18,24 +18,6 @@ namespace Umbraco.Web.Cache #endregion - //#region ApplicationTreeCache - - //public static void RefreshAllApplicationTreeCache(this DistributedCache dc) - //{ - // dc.RefreshAll(ApplicationTreeCacheRefresher.UniqueId); - //} - - //#endregion - - //#region ApplicationCache - - //public static void RefreshAllApplicationCache(this DistributedCache dc) - //{ - // dc.RefreshAll(ApplicationCacheRefresher.UniqueId); - //} - - //#endregion - #region User cache public static void RemoveUserCache(this DistributedCache dc, int userId) @@ -74,7 +56,6 @@ namespace Umbraco.Web.Cache #endregion - #region TemplateCache public static void RefreshTemplateCache(this DistributedCache dc, int templateId) diff --git a/src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs b/src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs deleted file mode 100644 index f27941035a..0000000000 --- a/src/Umbraco.Web/Models/ContentEditing/IBackOfficeSection.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Models.ContentEditing -{ - - /// - /// Defines a back office section - /// - public interface IBackOfficeSection : IDiscoverable - { - string Alias { get; } - string Name { get; } - int SortOrder { get; } - } -} diff --git a/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs index 683fce36e8..5aa99e4652 100644 --- a/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/SectionMapperProfile.cs @@ -3,6 +3,7 @@ using AutoMapper; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Models.Mapping { diff --git a/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs b/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs deleted file mode 100644 index ba48c9e240..0000000000 --- a/src/Umbraco.Web/Models/Trees/ApplicationDefinitions.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Web.Models.ContentEditing; - -namespace Umbraco.Web.Models.Trees -{ - /// - /// Defines the back office content section - /// - public class ContentBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Content; - public string Name => "Content"; - public int SortOrder => 0; - } - - /// - /// Defines the back office media section - /// - public class MediaBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Media; - public string Name => "Media"; - public int SortOrder => 1; - } - - /// - /// Defines the back office settings section - /// - public class SettingsBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Settings; - public string Name => "Settings"; - public int SortOrder => 2; - } - - /// - /// Defines the back office packages section - /// - public class PackagesBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Packages; - public string Name => "Packages"; - public int SortOrder => 3; - } - - /// - /// Defines the back office users section - /// - public class UsersBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Users; - public string Name => "Users"; - public int SortOrder => 4; - } - - /// - /// Defines the back office members section - /// - public class MembersBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Members; - public string Name => "Members"; - public int SortOrder => 5; - } - - /// - /// Defines the back office translation section - /// - public class TranslationBackOfficeSectionDefinition : IBackOfficeSection - { - public string Alias => Constants.Applications.Translation; - public string Name => "Translation"; - public int SortOrder => 6; - } -} diff --git a/src/Umbraco.Web/Models/Trees/IBackOfficeSection.cs b/src/Umbraco.Web/Models/Trees/IBackOfficeSection.cs new file mode 100644 index 0000000000..0cc505fb19 --- /dev/null +++ b/src/Umbraco.Web/Models/Trees/IBackOfficeSection.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Web.Models.Trees +{ + + /// + /// Defines a back office section + /// + public interface IBackOfficeSection + { + string Alias { get; } + string Name { get; } + } +} diff --git a/src/Umbraco.Web/Models/Trees/SectionRootNode.cs b/src/Umbraco.Web/Models/Trees/TreeRootNode.cs similarity index 100% rename from src/Umbraco.Web/Models/Trees/SectionRootNode.cs rename to src/Umbraco.Web/Models/Trees/TreeRootNode.cs diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 047d080a88..134ed7b1d0 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -25,6 +25,7 @@ using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.PublishedContent; +using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -195,9 +196,15 @@ namespace Umbraco.Web.Runtime .Append() .Append(); - // register back office sections + // register back office sections in the order we want them rendered composition.WithCollectionBuilder() - .Add(() => composition.TypeLoader.GetTypes()); + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); // register back office trees foreach (var treeControllerType in umbracoApiControllerTypes) diff --git a/src/Umbraco.Web/Services/ISectionService.cs b/src/Umbraco.Web/Services/ISectionService.cs index c325020cf1..f0a16dc965 100644 --- a/src/Umbraco.Web/Services/ISectionService.cs +++ b/src/Umbraco.Web/Services/ISectionService.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.ContentEditing; using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Services { diff --git a/src/Umbraco.Web/Services/ITreeService.cs b/src/Umbraco.Web/Services/ITreeService.cs index ce734cc5e4..17998ae1a7 100644 --- a/src/Umbraco.Web/Services/ITreeService.cs +++ b/src/Umbraco.Web/Services/ITreeService.cs @@ -29,15 +29,7 @@ namespace Umbraco.Web.Services /// The application alias. /// Returns a ApplicationTree Array IEnumerable GetApplicationTrees(string applicationAlias); - - ///// - ///// Gets the application tree for the applcation with the specified alias - ///// - ///// The application alias. - ///// - ///// Returns a ApplicationTree Array - //IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized); - + /// /// Gets the grouped application trees for the application with the specified alias /// diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index bb154976f0..e6af27534c 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -25,270 +25,31 @@ namespace Umbraco.Web.Services private readonly IUserService _userService; private readonly BackOfficeSectionCollection _sectionCollection; - private readonly Lazy> _allAvailableSections; - //private readonly IApplicationTreeService _applicationTreeService; - //private readonly IScopeProvider _scopeProvider; - private readonly CacheHelper _cache; - //internal const string AppConfigFileName = "applications.config"; - //private static string _appConfig; - //private static readonly object Locker = new object(); - public SectionService( IUserService userService, - BackOfficeSectionCollection sectionCollection, - CacheHelper cache) + BackOfficeSectionCollection sectionCollection) { - //_applicationTreeService = applicationTreeService ?? throw new ArgumentNullException(nameof(applicationTreeService)); - _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _userService = userService; _sectionCollection = sectionCollection; - //_scopeProvider = scopeProvider; - //_allAvailableSections = new Lazy>(() => new LazyEnumerableSections()); } - - - ///// - ///// gets/sets the application.config file path - ///// - ///// - ///// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath - ///// - //internal static string AppConfigFilePath - //{ - // get - // { - // if (string.IsNullOrWhiteSpace(_appConfig)) - // { - // _appConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + AppConfigFileName); - // } - // return _appConfig; - // } - // set => _appConfig = value; - //} - + /// /// The cache storage for all applications /// - public IEnumerable GetSections() - { - return _sectionCollection; - } + public IEnumerable GetSections() => _sectionCollection; - //internal void LoadXml(Func callback, bool saveAfterCallbackIfChanged) - //{ - // lock (Locker) - // { - // var doc = File.Exists(AppConfigFilePath) - // ? XDocument.Load(AppConfigFilePath) - // : XDocument.Parse(""); - - // if (doc.Root != null) - // { - // var changed = callback.Invoke(doc); - - // if (saveAfterCallbackIfChanged && changed) - // { - // //ensure the folder is created! - // Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath)); - - // doc.Save(AppConfigFilePath); - - // //remove the cache so it gets re-read ... SD: I'm leaving this here even though it - // // is taken care of by events as well, I think unit tests may rely on it being cleared here. - // _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); - // } - // } - // } - //} - - /// - /// Get the user's allowed sections - /// - /// - /// + /// public IEnumerable GetAllowedSections(int userId) { - var user = _userService.GetUserById(userId); if (user == null) - { throw new InvalidOperationException("No user found with id " + userId); - } return GetSections().Where(x => user.AllowedSections.Contains(x.Alias)); } - /// - /// Gets the application by its alias. - /// - /// The application alias. - /// - public IBackOfficeSection GetByAlias(string appAlias) - { - return GetSections().FirstOrDefault(t => t.Alias == appAlias); - } - - ///// - ///// Creates a new applcation if no application with the specified alias is found. - ///// - ///// The application name. - ///// The application alias. - ///// The application icon, which has to be located in umbraco/images/tray folder. - //public void MakeNew(string name, string alias, string icon) - //{ - // var sections = GetSections(); - // var nextSortOrder = sections.Any() ? sections.Max(x => x.SortOrder) + 1 : 1; - // MakeNew(name, alias, icon, nextSortOrder); - //} - - ///// - ///// Makes the new. - ///// - ///// The name. - ///// The alias. - ///// The icon. - ///// The sort order. - //public void MakeNew(string name, string alias, string icon, int sortOrder) - //{ - // if (GetSections().All(x => x.Alias != alias)) - // { - // LoadXml(doc => - // { - // doc.Root.Add(new XElement("add", - // new XAttribute("alias", alias), - // new XAttribute("name", name), - // new XAttribute("icon", icon), - // new XAttribute("sortOrder", sortOrder))); - // return true; - // }, true); - - // //raise event - // OnNew(this /*new Section(name, alias, sortOrder)*/, new EventArgs()); - // } - //} - - ///// - ///// Deletes the section - ///// - //public void DeleteSection(Section section) - //{ - // lock (Locker) - // { - // //delete the assigned applications - // using (var scope = _scopeProvider.CreateScope()) - // { - // scope.Database.Execute("delete from umbracoUserGroup2App where app = @appAlias", - // new { appAlias = section.Alias }); - // scope.Complete(); - // } - - // //delete the assigned trees - // var trees = _applicationTreeService.GetApplicationTrees(section.Alias); - // foreach (var t in trees) - // { - // _applicationTreeService.DeleteTree(t); - // } - - // LoadXml(doc => - // { - // doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias) - // .Remove(); - - // return true; - // }, true); - - // //raise event - // OnDeleted(this, new EventArgs()); - // } - //} - - //private List
ReadFromXmlAndSort() - //{ - // var tmp = new List
(); - - // LoadXml(doc => - // { - // foreach (var addElement in doc.Root.Elements("add").OrderBy(x => - // { - // var sortOrderAttr = x.Attribute("sortOrder"); - // return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0; - // })) - // { - // var sortOrderAttr = addElement.Attribute("sortOrder"); - // tmp.Add(new Section(addElement.Attribute("name").Value, - // addElement.Attribute("alias").Value, - // sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0)); - // } - // return false; - // }, false); - - // return tmp; - //} - - //internal static event TypedEventHandler Deleted; - //private static void OnDeleted(ISectionService app, EventArgs args) - //{ - // if (Deleted != null) - // { - // Deleted(app, args); - // } - //} - - //internal static event TypedEventHandler New; - //private static void OnNew(ISectionService app, EventArgs args) - //{ - // if (New != null) - // { - // New(app, args); - // } - //} - - ///// - ///// This class is here so that we can provide lazy access to tree scanning for when it is needed - ///// - //private class LazyEnumerableSections : IEnumerable
- //{ - // public LazyEnumerableSections() - // { - // _lazySections = new Lazy>(() => - // { - // // Load all Applications by attribute and add them to the XML config - - // //don't cache the result of this because it is only used once during app startup, caching will just add a bit more mem overhead for no reason - // var types = Current.TypeLoader.GetTypesWithAttribute(cache: false); // fixme - inject - - // //since applications don't populate their metadata from the attribute and because it is an interface, - // //we need to interrogate the attributes for the data. Would be better to have a base class that contains - // //metadata populated by the attribute. Oh well i guess. - // var attrs = types.Select(x => x.GetCustomAttributes(false).Single()); - // return attrs.Select(x => new Section(x.Name, x.Alias, x.SortOrder)).ToArray(); - // }); - // } - - // private readonly Lazy> _lazySections; - - // /// - // /// Returns an enumerator that iterates through the collection. - // /// - // /// - // /// A that can be used to iterate through the collection. - // /// - // public IEnumerator
GetEnumerator() - // { - // return _lazySections.Value.GetEnumerator(); - // } - - // /// - // /// Returns an enumerator that iterates through a collection. - // /// - // /// - // /// An object that can be used to iterate through the collection. - // /// - // IEnumerator IEnumerable.GetEnumerator() - // { - // return GetEnumerator(); - // } - //} - + /// + public IBackOfficeSection GetByAlias(string appAlias) => GetSections().FirstOrDefault(t => t.Alias == appAlias); + } } diff --git a/src/Umbraco.Web/Services/TreeService.cs b/src/Umbraco.Web/Services/TreeService.cs index cf010f1480..670f57ce49 100644 --- a/src/Umbraco.Web/Services/TreeService.cs +++ b/src/Umbraco.Web/Services/TreeService.cs @@ -1,237 +1,22 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Xml.Linq; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Events; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Composing; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Core.Services; -using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Trees; namespace Umbraco.Web.Services { internal class TreeService : ITreeService { - private readonly ILogger _logger; private readonly TreeCollection _treeCollection; - private static readonly object Locker = new object(); private readonly Lazy>> _groupedTrees; - public TreeService(ILogger logger, TreeCollection treeCollection) + public TreeService(TreeCollection treeCollection) { - _logger = logger; _treeCollection = treeCollection; _groupedTrees = new Lazy>>(InitGroupedTrees); } - ///// - ///// gets/sets the trees.config file path - ///// - ///// - ///// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath - ///// - //internal static string TreeConfigFilePath - //{ - // get - // { - // if (string.IsNullOrWhiteSpace(_treeConfig)) - // { - // _treeConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + TreeConfigFileName); - // } - // return _treeConfig; - // } - // set { _treeConfig = value; } - //} - - ///// - ///// The main entry point to get application trees - ///// - ///// - ///// This lazily on first access will scan for plugin trees and ensure the trees.config is up-to-date with the plugins. If plugins - ///// haven't changed on disk then the file will not be saved. The trees are all then loaded from this config file into cache and returned. - ///// - //private List GetAppTrees() - //{ - // return _cache.RuntimeCache.GetCacheItem>( - // CacheKeys.ApplicationTreeCacheKey, - // () => - // { - // var list = ReadFromXmlAndSort(); - - // //now we can check the non-volatile flag - // if (_allAvailableTrees != null) - // { - // var hasChanges = false; - - // LoadXml(doc => - // { - // //Now, load in the xml structure and update it with anything that is not declared there and save the file. - - // //NOTE: On the first iteration here, it will lazily scan all trees, etc... this is because this ienumerable is lazy - // // based on the ApplicationTreeRegistrar - and as noted there this is not an ideal way to do things but were stuck like this - // // currently because of the legacy assemblies and types not in the Core. - - // //Get all the trees not registered in the config (those not matching by alias casing will be detected as "unregistered") - // var unregistered = _allAvailableTrees.Value - // .Where(x => list.Any(l => l.Alias == x.Alias) == false) - // .ToArray(); - - // hasChanges = unregistered.Any(); - - // if (hasChanges == false) return false; - - // //add or edit the unregistered ones and re-save the file if any changes were found - // var count = 0; - // foreach (var tree in unregistered) - // { - // var existingElement = doc.Root.Elements("add").SingleOrDefault(x => - // string.Equals(x.Attribute("alias").Value, tree.Alias, - // StringComparison.InvariantCultureIgnoreCase) && - // string.Equals(x.Attribute("application").Value, tree.ApplicationAlias, - // StringComparison.InvariantCultureIgnoreCase)); - // if (existingElement != null) - // { - // existingElement.SetAttributeValue("alias", tree.Alias); - // } - // else - // { - // if (tree.Title.IsNullOrWhiteSpace()) - // { - // doc.Root.Add(new XElement("add", - // new XAttribute("initialize", tree.Initialize), - // new XAttribute("sortOrder", tree.SortOrder), - // new XAttribute("alias", tree.Alias), - // new XAttribute("application", tree.ApplicationAlias), - // new XAttribute("iconClosed", tree.IconClosed), - // new XAttribute("iconOpen", tree.IconOpened), - // new XAttribute("type", tree.Type))); - // } - // else - // { - // doc.Root.Add(new XElement("add", - // new XAttribute("initialize", tree.Initialize), - // new XAttribute("sortOrder", tree.SortOrder), - // new XAttribute("alias", tree.Alias), - // new XAttribute("application", tree.ApplicationAlias), - // new XAttribute("title", tree.Title), - // new XAttribute("iconClosed", tree.IconClosed), - // new XAttribute("iconOpen", tree.IconOpened), - // new XAttribute("type", tree.Type))); - // } - - // } - // count++; - // } - - // //don't save if there's no changes - // return count > 0; - // }, true); - - // if (hasChanges) - // { - // //If there were changes, we need to re-read the structures from the XML - // list = ReadFromXmlAndSort(); - // } - // } - - // return list; - // }, new TimeSpan(0, 10, 0)); - //} - - ///// - ///// Creates a new application tree. - ///// - ///// if set to true [initialize]. - ///// The sort order. - ///// The application alias. - ///// The alias. - ///// The title. - ///// The icon closed. - ///// The icon opened. - ///// The type. - //public void MakeNew(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type) - //{ - // LoadXml(doc => - // { - // var el = doc.Root.Elements("add").SingleOrDefault(x => x.Attribute("alias").Value == alias && x.Attribute("application").Value == applicationAlias); - - // if (el == null) - // { - // doc.Root.Add(new XElement("add", - // new XAttribute("initialize", initialize), - // new XAttribute("sortOrder", sortOrder), - // new XAttribute("alias", alias), - // new XAttribute("application", applicationAlias), - // new XAttribute("title", title), - // new XAttribute("iconClosed", iconClosed), - // new XAttribute("iconOpen", iconOpened), - // new XAttribute("type", type))); - // } - - // return true; - - // }, true); - - // OnNew(new ApplicationTree(initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, type), new EventArgs()); - //} - - ///// - ///// Saves this instance. - ///// - //public void SaveTree(ApplicationTree tree) - //{ - // LoadXml(doc => - // { - // var el = doc.Root.Elements("add").SingleOrDefault(x => x.Attribute("alias").Value == tree.Alias && x.Attribute("application").Value == tree.ApplicationAlias); - - // if (el != null) - // { - // el.RemoveAttributes(); - - // el.Add(new XAttribute("initialize", tree.Initialize)); - // el.Add(new XAttribute("sortOrder", tree.SortOrder)); - // el.Add(new XAttribute("alias", tree.Alias)); - // el.Add(new XAttribute("application", tree.ApplicationAlias)); - // el.Add(new XAttribute("title", tree.Title)); - // el.Add(new XAttribute("iconClosed", tree.IconClosed)); - // el.Add(new XAttribute("iconOpen", tree.IconOpened)); - // el.Add(new XAttribute("type", tree.Type)); - // } - - // return true; - - // }, true); - - // OnUpdated(tree, new EventArgs()); - //} - - ///// - ///// Deletes this instance. - ///// - //public void DeleteTree(ApplicationTree tree) - //{ - // LoadXml(doc => - // { - // doc.Root.Elements("add") - // .Where(x => x.Attribute("application") != null - // && x.Attribute("application").Value == tree.ApplicationAlias - // && x.Attribute("alias") != null && x.Attribute("alias").Value == tree.Alias).Remove(); - - // return true; - - // }, true); - - // OnDeleted(tree, new EventArgs()); - //} - /// public ApplicationTree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.TreeAlias == treeAlias); @@ -242,26 +27,6 @@ namespace Umbraco.Web.Services public IEnumerable GetApplicationTrees(string applicationAlias) => GetAll().Where(x => x.ApplicationAlias.InvariantEquals(applicationAlias)).OrderBy(x => x.SortOrder).ToList(); - ///// - ///// Gets the application tree for the applcation with the specified alias - ///// - ///// The application alias. - ///// - ///// Returns a ApplicationTree Array - //public IEnumerable GetApplicationTrees(string applicationAlias, bool onlyInitialized) - //{ - // var list = GetAppTrees().FindAll( - // t => - // { - // if (onlyInitialized) - // return (t.ApplicationAlias == applicationAlias && t.Initialize); - // return (t.ApplicationAlias == applicationAlias); - // } - // ); - - // return list.OrderBy(x => x.SortOrder).ToArray(); - //} - public IDictionary> GetGroupedApplicationTrees(string applicationAlias) { var result = new Dictionary>(); @@ -273,11 +38,10 @@ namespace Umbraco.Web.Services { foreach(var treeAliasInGroup in treeGroup) { - if (tree.TreeAlias == treeAliasInGroup) - { - if (resultGroup == null) resultGroup = new List(); - resultGroup.Add(tree); - } + if (tree.TreeAlias != treeAliasInGroup) continue; + + if (resultGroup == null) resultGroup = new List(); + resultGroup.Add(tree); } } if (resultGroup != null) @@ -302,169 +66,5 @@ namespace Umbraco.Web.Services return result; } - ///// - ///// Loads in the xml structure from disk if one is found, otherwise loads in an empty xml structure, calls the - ///// callback with the xml document and saves the structure back to disk if saveAfterCallback is true. - ///// - ///// - ///// - //internal void LoadXml(Func callback, bool saveAfterCallbackIfChanges) - //{ - // lock (Locker) - // { - // var doc = System.IO.File.Exists(TreeConfigFilePath) - // ? XDocument.Load(TreeConfigFilePath) - // : XDocument.Parse(""); - - // if (doc.Root != null) - // { - // var hasChanges = callback.Invoke(doc); - - // if (saveAfterCallbackIfChanges && hasChanges - // //Don't save it if it is empty, in some very rare cases if the app domain get's killed in the middle of this process - // // in some insane way the file saved will be empty. I'm pretty sure it's not actually anything to do with the xml doc and - // // more about the IO trying to save the XML doc, but it doesn't hurt to check. - // && doc.Root != null && doc.Root.Elements().Any()) - // { - // //ensures the folder exists - // Directory.CreateDirectory(Path.GetDirectoryName(TreeConfigFilePath)); - - // //saves it - // doc.Save(TreeConfigFilePath); - - // //remove the cache now that it has changed SD: I'm leaving this here even though it - // // is taken care of by events as well, I think unit tests may rely on it being cleared here. - // _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); - // } - // } - // } - //} - - //private List ReadFromXmlAndSort() - //{ - // var list = new List(); - - // //read in the xml file containing trees and convert them all to ApplicationTree instances - // LoadXml(doc => - // { - // foreach (var addElement in doc.Root.Elements("add").OrderBy(x => - // { - // var sortOrderAttr = x.Attribute("sortOrder"); - // return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0; - // })) - // { - // var applicationAlias = (string)addElement.Attribute("application"); - // var type = (string)addElement.Attribute("type"); - // var assembly = (string)addElement.Attribute("assembly"); - - // var clrType = Type.GetType(type); - // if (clrType == null) - // { - // _logger.Warn("The tree definition: {AddElement} could not be resolved to a .Net object type", addElement); - // continue; - // } - - // //check if the tree definition (applicationAlias + type + assembly) is already in the list - - // if (list.Any(tree => tree.ApplicationAlias.InvariantEquals(applicationAlias) && tree.GetRuntimeType() == clrType) == false) - // { - // list.Add(new ApplicationTree( - // addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value), - // addElement.Attribute("sortOrder") != null - // ? Convert.ToByte(addElement.Attribute("sortOrder").Value) - // : (byte)0, - // (string)addElement.Attribute("application"), - // (string)addElement.Attribute("alias"), - // (string)addElement.Attribute("title"), - // (string)addElement.Attribute("iconClosed"), - // (string)addElement.Attribute("iconOpen"), - // (string)addElement.Attribute("type"))); - // } - // } - - // return false; - - // }, false); - - // return list; - //} - - - //internal static event TypedEventHandler Deleted; - //private static void OnDeleted(ApplicationTree app, EventArgs args) - //{ - // if (Deleted != null) - // { - // Deleted(app, args); - // } - //} - - //internal static event TypedEventHandler New; - //private static void OnNew(ApplicationTree app, EventArgs args) - //{ - // if (New != null) - // { - // New(app, args); - // } - //} - - //internal static event TypedEventHandler Updated; - //private static void OnUpdated(ApplicationTree app, EventArgs args) - //{ - // if (Updated != null) - // { - // Updated(app, args); - // } - //} - - ///// - ///// This class is here so that we can provide lazy access to tree scanning for when it is needed - ///// - //private class LazyEnumerableTrees : IEnumerable - //{ - // public LazyEnumerableTrees(TypeLoader typeLoader) - // { - // _lazyTrees = new Lazy>(() => - // { - // var added = new List(); - - // // Load all Controller Trees by attribute - // var types = typeLoader.GetTypesWithAttribute(); // fixme inject - // //convert them to ApplicationTree instances - // var items = types - // .Select(x => (tree: x, treeAttribute: x.GetCustomAttributes(false).Single())) - // .Select(x => new ApplicationTree(x.treeAttribute.Initialize, x.treeAttribute.SortOrder, x.treeAttribute.ApplicationAlias, x.treeAttribute.Alias, x.treeAttribute.Title, x.treeAttribute.IconClosed, x.treeAttribute.IconOpen, x.tree.GetFullNameWithAssembly())) - // .ToArray(); - - // added.AddRange(items.Select(x => x.Alias)); - - // return items.ToArray(); - // }); - // } - - // private readonly Lazy> _lazyTrees; - - // /// - // /// Returns an enumerator that iterates through the collection. - // /// - // /// - // /// A that can be used to iterate through the collection. - // /// - // public IEnumerator GetEnumerator() - // { - // return _lazyTrees.Value.GetEnumerator(); - // } - - // /// - // /// Returns an enumerator that iterates through a collection. - // /// - // /// - // /// An object that can be used to iterate through the collection. - // /// - // IEnumerator IEnumerable.GetEnumerator() - // { - // return GetEnumerator(); - // } - //} } } diff --git a/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs b/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs index 2b5a78d758..54762e73d8 100644 --- a/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs +++ b/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Models.ContentEditing; using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { @@ -11,11 +12,4 @@ namespace Umbraco.Web.Trees : base(items) { } } - - public class BackOfficeSectionCollectionBuilder : LazyCollectionBuilderBase - { - protected override BackOfficeSectionCollectionBuilder This => this; - - //TODO: can we allow for re-ordering OOTB without exposing other methods? - } } diff --git a/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs b/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs new file mode 100644 index 0000000000..62d61a4090 --- /dev/null +++ b/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.Composing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + public class BackOfficeSectionCollectionBuilder : OrderedCollectionBuilderBase + { + protected override BackOfficeSectionCollectionBuilder This => this; + } +} diff --git a/src/Umbraco.Web/Trees/ContentBackOfficeSection.cs b/src/Umbraco.Web/Trees/ContentBackOfficeSection.cs new file mode 100644 index 0000000000..0109a6916d --- /dev/null +++ b/src/Umbraco.Web/Trees/ContentBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office content section + /// + public class ContentBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Content; + public string Name => "Content"; + } +} diff --git a/src/Umbraco.Web/Trees/ITree.cs b/src/Umbraco.Web/Trees/ITree.cs index 40be7338b0..f408ce5e60 100644 --- a/src/Umbraco.Web/Trees/ITree.cs +++ b/src/Umbraco.Web/Trees/ITree.cs @@ -1,5 +1,6 @@ namespace Umbraco.Web.Trees { + //fixme - we don't really use this, it is nice to have the treecontroller, attribute and ApplicationTree streamlined to implement this but it's not used public interface ITree { /// diff --git a/src/Umbraco.Web/Trees/MediaBackOfficeSection.cs b/src/Umbraco.Web/Trees/MediaBackOfficeSection.cs new file mode 100644 index 0000000000..aac4fd036f --- /dev/null +++ b/src/Umbraco.Web/Trees/MediaBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office media section + /// + public class MediaBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Media; + public string Name => "Media"; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/MembersBackOfficeSection.cs b/src/Umbraco.Web/Trees/MembersBackOfficeSection.cs new file mode 100644 index 0000000000..bfaead33d5 --- /dev/null +++ b/src/Umbraco.Web/Trees/MembersBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office members section + /// + public class MembersBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Members; + public string Name => "Members"; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/PackagesBackOfficeSection.cs b/src/Umbraco.Web/Trees/PackagesBackOfficeSection.cs new file mode 100644 index 0000000000..41f049c092 --- /dev/null +++ b/src/Umbraco.Web/Trees/PackagesBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office packages section + /// + public class PackagesBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Packages; + public string Name => "Packages"; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/SettingsBackOfficeSection.cs b/src/Umbraco.Web/Trees/SettingsBackOfficeSection.cs new file mode 100644 index 0000000000..623f593c30 --- /dev/null +++ b/src/Umbraco.Web/Trees/SettingsBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office settings section + /// + public class SettingsBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Settings; + public string Name => "Settings"; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/TranslationBackOfficeSection.cs b/src/Umbraco.Web/Trees/TranslationBackOfficeSection.cs new file mode 100644 index 0000000000..41254b3179 --- /dev/null +++ b/src/Umbraco.Web/Trees/TranslationBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office translation section + /// + public class TranslationBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Translation; + public string Name => "Translation"; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/TreeCollection.cs b/src/Umbraco.Web/Trees/TreeCollection.cs index c7b60dea16..51b79ce67b 100644 --- a/src/Umbraco.Web/Trees/TreeCollection.cs +++ b/src/Umbraco.Web/Trees/TreeCollection.cs @@ -16,31 +16,4 @@ namespace Umbraco.Web.Trees : base(items) { } } - - public class TreeCollectionBuilder : LazyCollectionBuilderBase - { - protected override TreeCollectionBuilder This => this; - - private readonly List _instances = new List(); - - public void AddTree(ApplicationTree tree) - { - _instances.Add(tree); - } - - protected override IEnumerable CreateItems(IFactory factory) - { - return _instances; - - //var items = base.CreateItems(factory).ToList(); - //throw new NotImplementedException(); - ////validate the items, no actions should exist that do not either expose notifications or permissions - //var invalidItems = items.Where(x => !x.CanBePermissionAssigned && !x.ShowInNotifier).ToList(); - //if (invalidItems.Count == 0) return items; - - //var invalidActions = string.Join(", ", invalidItems.Select(x => "'" + x.Alias + "'")); - //throw new InvalidOperationException($"Invalid actions {invalidActions}'. All {typeof(IAction)} implementations must be true for either {nameof(IAction.CanBePermissionAssigned)} or {nameof(IAction.ShowInNotifier)}."); - } - } - } diff --git a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs new file mode 100644 index 0000000000..2f92e72419 --- /dev/null +++ b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Trees +{ + //fixme - how will we allow users to modify these items? they will need to be able to change the ApplicationTree's registered (i.e. sort order, section) + public class TreeCollectionBuilder : CollectionBuilderBase + { + private readonly List _instances = new List(); + + public void AddTree(ApplicationTree tree) + { + _instances.Add(tree); + } + + protected override IEnumerable CreateItems(IFactory factory) => _instances; + } +} diff --git a/src/Umbraco.Web/Trees/UsersBackOfficeSection.cs b/src/Umbraco.Web/Trees/UsersBackOfficeSection.cs new file mode 100644 index 0000000000..90a65cb508 --- /dev/null +++ b/src/Umbraco.Web/Trees/UsersBackOfficeSection.cs @@ -0,0 +1,15 @@ +using Umbraco.Core; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office users section + /// + public class UsersBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.Users; + public string Name => "Users"; + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 0b1603c9e3..161f6c6689 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -166,8 +166,16 @@ + + + + + + + + - + @@ -591,7 +599,7 @@ - + @@ -673,7 +681,6 @@ - @@ -970,7 +977,7 @@ - + From 77dd816c514e13c487ce6b258af0dbdde4d932cb Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:06:22 +1100 Subject: [PATCH 147/223] more cleanup --- .../UI/Pages/UmbracoEnsuredPage.cs | 14 ++--- src/Umbraco.Web/Umbraco.Web.csproj | 1 - .../_Legacy/PackageActions/addApplication.cs | 61 ------------------- 3 files changed, 6 insertions(+), 70 deletions(-) delete mode 100644 src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs diff --git a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs index 9e632eabc9..cafdfb0e04 100644 --- a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs +++ b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs @@ -29,14 +29,12 @@ namespace Umbraco.Web.UI.Pages var treeAuth = this.GetType().GetCustomAttribute(true); if (treeAuth != null) { - throw new NotImplementedException(); - - //var treeByAlias = Current.Services.ApplicationTreeService - // .GetByAlias(treeAuth.TreeAlias); - //if (treeByAlias != null) - //{ - // CurrentApp = treeByAlias.ApplicationAlias; - //} + var treeByAlias = Current.TreeService + .GetByAlias(treeAuth.TreeAlias); + if (treeByAlias != null) + { + CurrentApp = treeByAlias.ApplicationAlias; + } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 161f6c6689..8c1a0639c4 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1138,7 +1138,6 @@ - diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs deleted file mode 100644 index c6d5ba30d9..0000000000 --- a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs +++ /dev/null @@ -1,61 +0,0 @@ -//using System; -//using System.Xml; -//using System.Xml.Linq; -//using Umbraco.Core; -//using Umbraco.Core._Legacy.PackageActions; -//using Umbraco.Web.Composing; - -//namespace Umbraco.Web._Legacy.PackageActions -//{ -// /// -// /// This class implements the IPackageAction Interface, used to execute code when packages are installed. -// /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. -// /// -// public class AddApplication : IPackageAction -// { - -// #region IPackageAction Members - -// /// -// /// Installs a new application in umbraco. -// /// -// /// Name of the package. -// /// The XML data. -// /// -// /// -// /// -// /// true if successfull -// public bool Execute(string packageName, XElement xmlData) -// { -// string name = xmlData.AttributeValue("appName"); -// string alias = xmlData.AttributeValue("appAlias"); -// string icon = xmlData.AttributeValue("appIcon"); - -// Current.Services.SectionService.MakeNew(name, alias, icon); - -// return true; -// } - -// public bool Undo(string packageName, XElement xmlData) -// { -// string alias = xmlData.AttributeValue("appAlias"); -// var section = Current.Services.SectionService.GetByAlias(alias); -// if (section != null) -// { -// Current.Services.SectionService.DeleteSection(section); -// } -// return true; -// } -// /// -// /// Action alias. -// /// -// /// -// public string Alias() -// { -// return "addApplication"; -// } - -// #endregion - -// } -//} From 9df1773b78d38a3ff59c65193702ef7e3ba73cfe Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:08:58 +1100 Subject: [PATCH 148/223] more cleanup --- build/NuSpecs/UmbracoCms.nuspec | 2 -- src/Umbraco.Core/Composing/TypeLoader.cs | 4 +-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 11 ------ .../config/applications.Release.config | 11 ------ src/Umbraco.Web.UI/config/applications.config | 11 ------ .../config/trees.Release.config | 34 ------------------ src/Umbraco.Web.UI/config/trees.config | 36 ------------------- 7 files changed, 1 insertion(+), 108 deletions(-) delete mode 100644 src/Umbraco.Web.UI/config/applications.Release.config delete mode 100644 src/Umbraco.Web.UI/config/applications.config delete mode 100644 src/Umbraco.Web.UI/config/trees.Release.config delete mode 100644 src/Umbraco.Web.UI/config/trees.config diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index 3cb3d0d875..a188377c19 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -52,10 +52,8 @@ - - diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index acb12ab575..4c4139848d 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -185,9 +185,7 @@ namespace Umbraco.Core.Composing // the app code folder and everything in it new Tuple(new DirectoryInfo(IOHelper.MapPath("~/App_Code")), false), // global.asax (the app domain also monitors this, if it changes will do a full restart) - new Tuple(new FileInfo(IOHelper.MapPath("~/global.asax")), false), - // trees.config - use the contents to create the hash since this gets resaved on every app startup! - new Tuple(new FileInfo(IOHelper.MapPath(SystemDirectories.Config + "/trees.config")), true) + new Tuple(new FileInfo(IOHelper.MapPath("~/global.asax")), false) }, _logger); return _currentAssembliesHash; diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index c21bf7fef6..778ab188cd 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -241,9 +241,6 @@ umbracoSettings.config Designer - - trees.config - tinyMceConfig.config Designer @@ -301,14 +298,6 @@ - - - Designer - - - applications.config - Designer - diff --git a/src/Umbraco.Web.UI/config/applications.Release.config b/src/Umbraco.Web.UI/config/applications.Release.config deleted file mode 100644 index 5c8dee3b8a..0000000000 --- a/src/Umbraco.Web.UI/config/applications.Release.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/Umbraco.Web.UI/config/applications.config b/src/Umbraco.Web.UI/config/applications.config deleted file mode 100644 index 5c8dee3b8a..0000000000 --- a/src/Umbraco.Web.UI/config/applications.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/Umbraco.Web.UI/config/trees.Release.config b/src/Umbraco.Web.UI/config/trees.Release.config deleted file mode 100644 index bd75e97c38..0000000000 --- a/src/Umbraco.Web.UI/config/trees.Release.config +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config deleted file mode 100644 index 5892545682..0000000000 --- a/src/Umbraco.Web.UI/config/trees.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 1a734141f18a6e25493e1b6fef7ab0188b5ec3d6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:31:29 +1100 Subject: [PATCH 149/223] Allows package manifest to declare a section --- src/Umbraco.Core/Manifest/ManifestParser.cs | 7 +++- src/Umbraco.Core/Manifest/PackageManifest.cs | 7 ++++ .../Manifest/ManifestParserTests.cs | 18 ++++++++++ src/Umbraco.Web/Services/SectionService.cs | 13 ------- .../Trees/BackOfficeSectionCollection.cs | 1 + .../BackOfficeSectionCollectionBuilder.cs | 35 ++++++++++++++++++- 6 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index 59753df66a..28493fe20f 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -101,6 +101,7 @@ namespace Umbraco.Core.Manifest var gridEditors = new List(); var contentApps = new List(); var dashboards = new List(); + var sections = new Dictionary(); foreach (var manifest in manifests) { @@ -111,6 +112,9 @@ namespace Umbraco.Core.Manifest if (manifest.GridEditors != null) gridEditors.AddRange(manifest.GridEditors); if (manifest.ContentApps != null) contentApps.AddRange(manifest.ContentApps); if (manifest.Dashboards != null) dashboards.AddRange(manifest.Dashboards); + if (manifest.Sections != null) + foreach (var (key, value) in manifest.Sections) + sections[key] = value; } return new PackageManifest @@ -121,7 +125,8 @@ namespace Umbraco.Core.Manifest ParameterEditors = parameterEditors.ToArray(), GridEditors = gridEditors.ToArray(), ContentApps = contentApps.ToArray(), - Dashboards = dashboards.ToArray() + Dashboards = dashboards.ToArray(), + Sections = sections }; } diff --git a/src/Umbraco.Core/Manifest/PackageManifest.cs b/src/Umbraco.Core/Manifest/PackageManifest.cs index cd806ac847..a0546f3629 100644 --- a/src/Umbraco.Core/Manifest/PackageManifest.cs +++ b/src/Umbraco.Core/Manifest/PackageManifest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Newtonsoft.Json; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.PropertyEditors; @@ -30,5 +31,11 @@ namespace Umbraco.Core.Manifest [JsonProperty("dashboards")] public ManifestDashboardDefinition[] Dashboards { get; set; } = Array.Empty(); + + /// + /// Declares the back office sections that this package installs + /// + [JsonProperty("sections")] + public IReadOnlyDictionary Sections { get; set; } = new Dictionary(); } } diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs index ce3d1d705c..9970d5f6b0 100644 --- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs @@ -429,5 +429,23 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual(1, db1.Sections.Length); Assert.AreEqual("forms", db1.Sections[0]); } + + [Test] + public void CanParseManifest_Sections() + { + const string json = @"{'sections': { + 'content': 'Content', + 'hello': 'World' + } +}"; + + var manifest = _parser.ParseManifest(json); + Assert.AreEqual(2, manifest.Sections.Count); + Assert.AreEqual("content", manifest.Sections.Keys.ElementAt(0)); + Assert.AreEqual("hello", manifest.Sections.Keys.ElementAt(1)); + Assert.AreEqual("Content", manifest.Sections["content"]); + Assert.AreEqual("World", manifest.Sections["hello"]); + + } } } diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index e6af27534c..b17b9f965a 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -1,22 +1,9 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Xml.Linq; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Events; -using Umbraco.Core.IO; -using Umbraco.Core.Models; -using Umbraco.Core.Composing; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Core.Scoping; using Umbraco.Core.Services; -using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Trees; using Umbraco.Web.Trees; -using File = System.IO.File; namespace Umbraco.Web.Services { diff --git a/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs b/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs index 54762e73d8..fdeb812363 100644 --- a/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs +++ b/src/Umbraco.Web/Trees/BackOfficeSectionCollection.cs @@ -11,5 +11,6 @@ namespace Umbraco.Web.Trees public BackOfficeSectionCollection(IEnumerable items) : base(items) { } + } } diff --git a/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs b/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs index 62d61a4090..ec5833f79c 100644 --- a/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs +++ b/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs @@ -1,10 +1,43 @@ -using Umbraco.Core.Composing; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Composing; +using Umbraco.Core.Manifest; +using Umbraco.Core.Models.ContentEditing; using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { + //fixme: how can a developer re-sort the items in this collection ? public class BackOfficeSectionCollectionBuilder : OrderedCollectionBuilderBase { protected override BackOfficeSectionCollectionBuilder This => this; + + // need to inject dependencies in the collection, so override creation + public override BackOfficeSectionCollection CreateCollection(IFactory factory) + { + return new BackOfficeSectionCollection(CreateItems(factory)); + } + + protected override IEnumerable CreateItems(IFactory factory) + { + // get the manifest parser just-in-time - injecting it in the ctor would mean that + // simply getting the builder in order to configure the collection, would require + // its dependencies too, and that can create cycles or other oddities + var manifestParser = factory.GetInstance(); + + return base.CreateItems(factory).Concat(manifestParser.Manifest.Sections.Select(x => new ManifestBackOfficeSection(x.Key, x.Value))); + } + + private class ManifestBackOfficeSection : IBackOfficeSection + { + public ManifestBackOfficeSection(string @alias, string name) + { + Alias = alias; + Name = name; + } + + public string Alias { get; } + public string Name { get; } + } } } From 356209e013f93cf9b7b890a3c7067ce6830dac42 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:33:38 +1100 Subject: [PATCH 150/223] renames ApplicationTree to just Tree --- src/Umbraco.Web/Editors/EntityController.cs | 2 +- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 2 +- src/Umbraco.Web/Services/ITreeService.cs | 8 ++++---- src/Umbraco.Web/Services/TreeService.cs | 14 +++++++------- src/Umbraco.Web/Trees/ApplicationTreeController.cs | 8 ++++---- .../Trees/{ApplicationTree.cs => Tree.cs} | 4 ++-- src/Umbraco.Web/Trees/TreeCollection.cs | 4 ++-- src/Umbraco.Web/Trees/TreeCollectionBuilder.cs | 8 ++++---- src/Umbraco.Web/Trees/TreeController.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- 10 files changed, 27 insertions(+), 27 deletions(-) rename src/Umbraco.Web/Trees/{ApplicationTree.cs => Tree.cs} (91%) diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index ca1a6a12bb..e376f9ad5b 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -148,7 +148,7 @@ namespace Umbraco.Web.Editors var searchableTreeAttribute = searchableTree.Value.SearchableTree.GetType().GetCustomAttribute(false); - result[ApplicationTree.GetRootNodeDisplayName(tree, Services.TextService)] = new TreeSearchResult + result[Tree.GetRootNodeDisplayName(tree, Services.TextService)] = new TreeSearchResult { Results = searchableTree.Value.SearchableTree.Search(query, 200, 0, out var total), TreeAlias = searchableTree.Key, diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 134ed7b1d0..f21c040a37 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -211,7 +211,7 @@ namespace Umbraco.Web.Runtime { var attribute = treeControllerType.GetCustomAttribute(false); if (attribute == null) continue; - var tree = new ApplicationTree(attribute.SortOrder, attribute.ApplicationAlias, attribute.TreeAlias, attribute.TreeTitle, treeControllerType, attribute.IsSingleNodeTree); + var tree = new Tree(attribute.SortOrder, attribute.ApplicationAlias, attribute.TreeAlias, attribute.TreeTitle, treeControllerType, attribute.IsSingleNodeTree); composition.WithCollectionBuilder().AddTree(tree); } } diff --git a/src/Umbraco.Web/Services/ITreeService.cs b/src/Umbraco.Web/Services/ITreeService.cs index 17998ae1a7..5172e4b7b7 100644 --- a/src/Umbraco.Web/Services/ITreeService.cs +++ b/src/Umbraco.Web/Services/ITreeService.cs @@ -15,27 +15,27 @@ namespace Umbraco.Web.Services /// /// The tree alias. /// An ApplicationTree instance - ApplicationTree GetByAlias(string treeAlias); + Tree GetByAlias(string treeAlias); /// /// Gets all applicationTrees registered in umbraco from the umbracoAppTree table.. /// /// Returns a ApplicationTree Array - IEnumerable GetAll(); + IEnumerable GetAll(); /// /// Gets the application tree for the applcation with the specified alias /// /// The application alias. /// Returns a ApplicationTree Array - IEnumerable GetApplicationTrees(string applicationAlias); + IEnumerable GetApplicationTrees(string applicationAlias); /// /// Gets the grouped application trees for the application with the specified alias /// /// /// - IDictionary> GetGroupedApplicationTrees(string applicationAlias); + IDictionary> GetGroupedApplicationTrees(string applicationAlias); } } diff --git a/src/Umbraco.Web/Services/TreeService.cs b/src/Umbraco.Web/Services/TreeService.cs index 670f57ce49..8389c27a19 100644 --- a/src/Umbraco.Web/Services/TreeService.cs +++ b/src/Umbraco.Web/Services/TreeService.cs @@ -18,29 +18,29 @@ namespace Umbraco.Web.Services } /// - public ApplicationTree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.TreeAlias == treeAlias); + public Tree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.TreeAlias == treeAlias); /// - public IEnumerable GetAll() => _treeCollection; + public IEnumerable GetAll() => _treeCollection; /// - public IEnumerable GetApplicationTrees(string applicationAlias) + public IEnumerable GetApplicationTrees(string applicationAlias) => GetAll().Where(x => x.ApplicationAlias.InvariantEquals(applicationAlias)).OrderBy(x => x.SortOrder).ToList(); - public IDictionary> GetGroupedApplicationTrees(string applicationAlias) + public IDictionary> GetGroupedApplicationTrees(string applicationAlias) { - var result = new Dictionary>(); + var result = new Dictionary>(); var foundTrees = GetApplicationTrees(applicationAlias).ToList(); foreach(var treeGroup in _groupedTrees.Value) { - List resultGroup = null; + List resultGroup = null; foreach(var tree in foundTrees) { foreach(var treeAliasInGroup in treeGroup) { if (tree.TreeAlias != treeAliasInGroup) continue; - if (resultGroup == null) resultGroup = new List(); + if (resultGroup == null) resultGroup = new List(); resultGroup.Add(tree); } } diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 0e405ca3f3..5a0f72c8dc 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -160,7 +160,7 @@ namespace Umbraco.Web.Trees /// /// /// - private async Task GetRootForMultipleAppTree(ApplicationTree tree, FormDataCollection queryStrings) + private async Task GetRootForMultipleAppTree(Tree tree, FormDataCollection queryStrings) { if (tree == null) throw new ArgumentNullException(nameof(tree)); try @@ -189,7 +189,7 @@ namespace Umbraco.Web.Trees /// /// /// - private async Task GetRootForSingleAppTree(ApplicationTree tree, string id, FormDataCollection queryStrings, string application) + private async Task GetRootForSingleAppTree(Tree tree, string id, FormDataCollection queryStrings, string application) { var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture); if (tree == null) throw new ArgumentNullException(nameof(tree)); @@ -234,7 +234,7 @@ namespace Umbraco.Web.Trees /// /// This ensures that authorization filters are applied to the sub request /// - private async Task> TryGetRootNodeFromControllerTree(ApplicationTree appTree, FormDataCollection formCollection, HttpControllerContext controllerContext) + private async Task> TryGetRootNodeFromControllerTree(Tree appTree, FormDataCollection formCollection, HttpControllerContext controllerContext) { //instantiate it, since we are proxying, we need to setup the instance with our current context var instance = (TreeController)DependencyResolver.Current.GetService(appTree.TreeControllerType); @@ -290,7 +290,7 @@ namespace Umbraco.Web.Trees /// /// /// - private Attempt TryLoadFromControllerTree(ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext) + private Attempt TryLoadFromControllerTree(Tree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext) { // instantiate it, since we are proxying, we need to setup the instance with our current context var instance = (TreeController)DependencyResolver.Current.GetService(appTree.TreeControllerType); diff --git a/src/Umbraco.Web/Trees/ApplicationTree.cs b/src/Umbraco.Web/Trees/Tree.cs similarity index 91% rename from src/Umbraco.Web/Trees/ApplicationTree.cs rename to src/Umbraco.Web/Trees/Tree.cs index 5ed9847be3..3bac5bae58 100644 --- a/src/Umbraco.Web/Trees/ApplicationTree.cs +++ b/src/Umbraco.Web/Trees/Tree.cs @@ -6,9 +6,9 @@ using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { [DebuggerDisplay("Tree - {TreeAlias} ({ApplicationAlias})")] - public class ApplicationTree : ITree + public class Tree : ITree { - public ApplicationTree(int sortOrder, string applicationAlias, string alias, string title, Type treeControllerType, bool isSingleNodeTree) + public Tree(int sortOrder, string applicationAlias, string alias, string title, Type treeControllerType, bool isSingleNodeTree) { SortOrder = sortOrder; ApplicationAlias = applicationAlias; diff --git a/src/Umbraco.Web/Trees/TreeCollection.cs b/src/Umbraco.Web/Trees/TreeCollection.cs index 51b79ce67b..a7bfe52295 100644 --- a/src/Umbraco.Web/Trees/TreeCollection.cs +++ b/src/Umbraco.Web/Trees/TreeCollection.cs @@ -10,9 +10,9 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Trees { - public class TreeCollection : BuilderCollectionBase + public class TreeCollection : BuilderCollectionBase { - public TreeCollection(IEnumerable items) + public TreeCollection(IEnumerable items) : base(items) { } } diff --git a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs index 2f92e72419..143b8e308b 100644 --- a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs +++ b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs @@ -4,15 +4,15 @@ using Umbraco.Core.Composing; namespace Umbraco.Web.Trees { //fixme - how will we allow users to modify these items? they will need to be able to change the ApplicationTree's registered (i.e. sort order, section) - public class TreeCollectionBuilder : CollectionBuilderBase + public class TreeCollectionBuilder : CollectionBuilderBase { - private readonly List _instances = new List(); + private readonly List _instances = new List(); - public void AddTree(ApplicationTree tree) + public void AddTree(Tree tree) { _instances.Add(tree); } - protected override IEnumerable CreateItems(IFactory factory) => _instances; + protected override IEnumerable CreateItems(IFactory factory) => _instances; } } diff --git a/src/Umbraco.Web/Trees/TreeController.cs b/src/Umbraco.Web/Trees/TreeController.cs index 63e8f5aad5..553cda255e 100644 --- a/src/Umbraco.Web/Trees/TreeController.cs +++ b/src/Umbraco.Web/Trees/TreeController.cs @@ -28,7 +28,7 @@ namespace Umbraco.Web.Trees } /// - public override string RootNodeDisplayName => ApplicationTree.GetRootNodeDisplayName(this, Services.TextService); + public override string RootNodeDisplayName => Tree.GetRootNodeDisplayName(this, Services.TextService); /// public override string TreeAlias => _attribute.TreeAlias; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 8c1a0639c4..23cbb7a416 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -174,7 +174,7 @@ - + From 6b9ba3c53c806b2943f531bb71e0fc247ee243e3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:50:59 +1100 Subject: [PATCH 151/223] Fixing tests --- src/Umbraco.Tests/Services/SectionServiceTests.cs | 9 +++------ src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 11 +++++++++++ src/Umbraco.Web/Services/SectionService.cs | 4 ++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Tests/Services/SectionServiceTests.cs b/src/Umbraco.Tests/Services/SectionServiceTests.cs index 9211755251..87fcde34ad 100644 --- a/src/Umbraco.Tests/Services/SectionServiceTests.cs +++ b/src/Umbraco.Tests/Services/SectionServiceTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using System.Linq; using System.Threading; +using Umbraco.Core.Composing; using Umbraco.Core.Models.Membership; using Umbraco.Tests.Testing; using Umbraco.Web.Services; @@ -15,15 +16,11 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] public class SectionServiceTests : TestWithSomeContentBase { - //fixme - private ISectionService SectionService => new SectionService(ServiceContext.UserService, null); - + private ISectionService SectionService => Factory.GetInstance(); [Test] public void SectionService_Can_Get_Allowed_Sections_For_User() { - //fixme - need to mock - // Arrange var user = CreateTestUser(); @@ -60,7 +57,7 @@ namespace Umbraco.Tests.Services Name = "Group B" }; userGroupB.AddAllowedSection("settings"); - userGroupB.AddAllowedSection("developer"); + userGroupB.AddAllowedSection("member"); ServiceContext.UserService.Save(userGroupB, new[] { user.Id }, false); return ServiceContext.UserService.GetUserById(user.Id); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 0a0999f2dc..ace50917ba 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -40,6 +40,7 @@ using Umbraco.Web.Composing.Composers; using Umbraco.Web.ContentApps; using Current = Umbraco.Core.Composing.Current; using Umbraco.Web.Routing; +using Umbraco.Web.Trees; namespace Umbraco.Tests.Testing { @@ -216,6 +217,16 @@ namespace Umbraco.Tests.Testing Composition.WithCollectionBuilder(); Composition.RegisterUnique(); Composition.RegisterUnique(); + + // register back office sections in the order we want them rendered + Composition.WithCollectionBuilder().Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + Composition.RegisterUnique(); } protected virtual void ComposeWtf() diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index b17b9f965a..089bdc5bd3 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -16,8 +16,8 @@ namespace Umbraco.Web.Services IUserService userService, BackOfficeSectionCollection sectionCollection) { - _userService = userService; - _sectionCollection = sectionCollection; + _userService = userService ?? throw new ArgumentNullException(nameof(userService)); + _sectionCollection = sectionCollection ?? throw new ArgumentNullException(nameof(sectionCollection)); } /// From 3f89558ddbc3d37081eb50ce5360f476839499ed Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 17:51:38 +1100 Subject: [PATCH 152/223] Fixing tests --- src/Umbraco.Tests/Composing/TypeFinderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/Composing/TypeFinderTests.cs b/src/Umbraco.Tests/Composing/TypeFinderTests.cs index 49c807b19f..2b9474310b 100644 --- a/src/Umbraco.Tests/Composing/TypeFinderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeFinderTests.cs @@ -90,7 +90,7 @@ namespace Umbraco.Tests.Composing Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree] typesFound = TypeFinder.FindClassesWithAttribute(new[] { typeof (UmbracoContext).Assembly }); - Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] + Assert.AreEqual(21, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] } private static IProfilingLogger GetTestProfilingLogger() From 67e47038217be35969e982195974c5441a518e65 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 17 Jan 2019 08:34:29 +0100 Subject: [PATCH 153/223] CacheHelper becomes AppCaches --- .../Cache/{CacheHelper.cs => AppCaches.cs} | 12 +++--- src/Umbraco.Core/Cache/CacheRefresherBase.cs | 10 ++--- .../Cache/JsonCacheRefresherBase.cs | 4 +- .../Cache/PayloadCacheRefresherBase.cs | 4 +- .../Cache/TypedCacheRefresherBase.cs | 6 +-- .../Composing/Composers/ServicesComposer.cs | 2 +- .../Composing/CompositionExtensions.cs | 4 +- src/Umbraco.Core/Composing/Current.cs | 4 +- .../Implement/AuditEntryRepository.cs | 2 +- .../Repositories/Implement/AuditRepository.cs | 2 +- .../Implement/ConsentRepository.cs | 2 +- .../Implement/ContentRepositoryBase.cs | 2 +- .../Implement/ContentTypeRepository.cs | 2 +- .../Implement/ContentTypeRepositoryBase.cs | 2 +- .../Implement/DataTypeContainerRepository.cs | 2 +- .../Implement/DataTypeRepository.cs | 2 +- .../Implement/DictionaryRepository.cs | 6 +-- .../Implement/DocumentBlueprintRepository.cs | 4 +- .../Implement/DocumentRepository.cs | 14 +++---- .../DocumentTypeContainerRepository.cs | 2 +- .../Implement/DomainRepository.cs | 2 +- .../Implement/EntityContainerRepository.cs | 2 +- .../Implement/ExternalLoginRepository.cs | 2 +- .../Implement/LanguageRepository.cs | 2 +- .../Repositories/Implement/MacroRepository.cs | 2 +- .../Repositories/Implement/MediaRepository.cs | 4 +- .../Implement/MediaTypeContainerRepository.cs | 2 +- .../Implement/MediaTypeRepository.cs | 2 +- .../Implement/MemberGroupRepository.cs | 2 +- .../Implement/MemberRepository.cs | 2 +- .../Implement/MemberTypeRepository.cs | 2 +- .../Implement/NPocoRepositoryBase.cs | 2 +- .../Implement/PermissionRepository.cs | 2 +- .../Implement/PublicAccessRepository.cs | 2 +- .../Implement/RedirectUrlRepository.cs | 2 +- .../Implement/RelationRepository.cs | 2 +- .../Implement/RelationTypeRepository.cs | 2 +- .../Implement/RepositoryBaseOfTIdTEntity.cs | 6 +-- .../Implement/ServerRegistrationRepository.cs | 2 +- .../Implement/SimpleGetRepository.cs | 2 +- .../Repositories/Implement/TagRepository.cs | 2 +- .../Implement/TemplateRepository.cs | 2 +- .../Implement/UserGroupRepository.cs | 10 ++--- .../Repositories/Implement/UserRepository.cs | 10 ++--- src/Umbraco.Core/Runtime/CoreRuntime.cs | 4 +- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- src/Umbraco.Tests/Macros/MacroTests.cs | 2 +- .../Models/Mapping/AutoMapperTests.cs | 2 +- .../Repositories/ContentTypeRepositoryTest.cs | 12 +++--- .../DataTypeDefinitionRepositoryTest.cs | 2 +- .../Repositories/DocumentRepositoryTest.cs | 28 ++++++------- .../Repositories/DomainRepositoryTest.cs | 12 +++--- .../Repositories/LanguageRepositoryTest.cs | 2 +- .../Repositories/MacroRepositoryTest.cs | 36 ++++++++--------- .../Repositories/MediaRepositoryTest.cs | 14 +++---- .../Repositories/MediaTypeRepositoryTest.cs | 4 +- .../Repositories/MemberRepositoryTest.cs | 8 ++-- .../Repositories/MemberTypeRepositoryTest.cs | 2 +- .../PublicAccessRepositoryTest.cs | 24 +++++------ .../RedirectUrlRepositoryTests.cs | 2 +- .../Repositories/RelationRepositoryTest.cs | 4 +- .../RelationTypeRepositoryTest.cs | 4 +- .../ServerRegistrationRepositoryTest.cs | 4 +- .../Repositories/TagRepositoryTest.cs | 18 ++++----- .../Repositories/TemplateRepositoryTest.cs | 10 ++--- .../Repositories/UserGroupRepositoryTest.cs | 4 +- .../Repositories/UserRepositoryTest.cs | 22 +++++----- .../Routing/RenderRouteHandlerTests.cs | 2 +- src/Umbraco.Tests/Runtimes/StandaloneTests.cs | 4 +- .../Scoping/ScopedRepositoryTests.cs | 4 +- .../Services/ContentServicePerformanceTest.cs | 40 +++++++++---------- .../Services/ContentServiceTests.cs | 10 ++--- .../Services/MacroServiceTests.cs | 2 +- .../Templates/TemplateRepositoryTests.cs | 2 +- .../TestControllerActivatorBase.cs | 2 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 2 +- .../Testing/TestingTests/MockTests.cs | 4 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 6 +-- .../Web/Mvc/SurfaceControllerTests.cs | 4 +- .../Cache/ApplicationCacheRefresher.cs | 8 ++-- .../Cache/ApplicationTreeCacheRefresher.cs | 8 ++-- .../Cache/ContentCacheRefresher.cs | 20 +++++----- .../Cache/ContentTypeCacheRefresher.cs | 10 ++--- .../Cache/DataTypeCacheRefresher.cs | 6 +-- .../Cache/DictionaryCacheRefresher.cs | 4 +- src/Umbraco.Web/Cache/DomainCacheRefresher.cs | 4 +- .../Cache/LanguageCacheRefresher.cs | 4 +- src/Umbraco.Web/Cache/MacroCacheRefresher.cs | 16 ++++---- src/Umbraco.Web/Cache/MediaCacheRefresher.cs | 10 ++--- src/Umbraco.Web/Cache/MemberCacheRefresher.cs | 12 +++--- .../Cache/MemberGroupCacheRefresher.cs | 6 +-- .../Cache/PublicAccessCacheRefresher.cs | 4 +- .../Cache/RelationTypeCacheRefresher.cs | 8 ++-- .../Cache/TemplateCacheRefresher.cs | 6 +-- src/Umbraco.Web/Cache/UserCacheRefresher.cs | 6 +-- .../Cache/UserGroupCacheRefresher.cs | 8 ++-- .../UserGroupPermissionsCacheRefresher.cs | 4 +- src/Umbraco.Web/CacheHelperExtensions.cs | 12 +++--- src/Umbraco.Web/Composing/Current.cs | 2 +- .../Controllers/UmbLoginController.cs | 2 +- .../Controllers/UmbLoginStatusController.cs | 2 +- .../Controllers/UmbProfileController.cs | 2 +- .../Controllers/UmbRegisterController.cs | 2 +- .../Editors/AuthenticationController.cs | 2 +- .../Editors/BackOfficeController.cs | 2 +- .../Editors/ContentTypeController.cs | 2 +- .../Editors/ContentTypeControllerBase.cs | 2 +- .../Editors/DashboardController.cs | 2 +- .../Editors/MediaTypeController.cs | 2 +- .../Editors/MemberTypeController.cs | 2 +- .../Editors/PackageInstallController.cs | 2 +- .../UmbracoAuthorizedJsonController.cs | 2 +- src/Umbraco.Web/Mvc/PluginController.cs | 6 +-- src/Umbraco.Web/Mvc/RenderMvcController.cs | 2 +- src/Umbraco.Web/Mvc/SurfaceController.cs | 2 +- .../Mvc/UmbracoAuthorizedController.cs | 2 +- src/Umbraco.Web/Mvc/UmbracoController.cs | 6 +-- .../Mvc/UmbracoViewPageOfTModel.cs | 6 +-- src/Umbraco.Web/Runtime/WebRuntime.cs | 2 +- src/Umbraco.Web/Security/MembershipHelper.cs | 4 +- .../Services/ApplicationTreeService.cs | 4 +- src/Umbraco.Web/Services/SectionService.cs | 4 +- src/Umbraco.Web/TagsController.cs | 2 +- .../WebApi/UmbracoApiController.cs | 2 +- .../WebApi/UmbracoApiControllerBase.cs | 6 +-- .../WebApi/UmbracoAuthorizedApiController.cs | 2 +- 126 files changed, 348 insertions(+), 348 deletions(-) rename src/Umbraco.Core/Cache/{CacheHelper.cs => AppCaches.cs} (83%) diff --git a/src/Umbraco.Core/Cache/CacheHelper.cs b/src/Umbraco.Core/Cache/AppCaches.cs similarity index 83% rename from src/Umbraco.Core/Cache/CacheHelper.cs rename to src/Umbraco.Core/Cache/AppCaches.cs index cd2225ae9d..7dd95624ef 100644 --- a/src/Umbraco.Core/Cache/CacheHelper.cs +++ b/src/Umbraco.Core/Cache/AppCaches.cs @@ -6,12 +6,12 @@ namespace Umbraco.Core.Cache /// /// Represents the application-wide caches. /// - public class CacheHelper + public class AppCaches { /// /// Initializes a new instance for use in the web /// - public CacheHelper() + public AppCaches() : this( new HttpRuntimeCacheProvider(HttpRuntime.Cache), new StaticCacheProvider(), @@ -23,7 +23,7 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance for use in the web /// - public CacheHelper(System.Web.Caching.Cache cache) + public AppCaches(System.Web.Caching.Cache cache) : this( new HttpRuntimeCacheProvider(cache), new StaticCacheProvider(), @@ -35,7 +35,7 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance based on the provided providers /// - public CacheHelper( + public AppCaches( IRuntimeCacheProvider httpCacheProvider, ICacheProvider staticCacheProvider, ICacheProvider requestCacheProvider, @@ -54,7 +54,7 @@ namespace Umbraco.Core.Cache /// When used by repositories, all cache policies apply, but the underlying caches do not cache anything. /// Used by tests. /// - public static CacheHelper Disabled { get; } = new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); + public static AppCaches Disabled { get; } = new AppCaches(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); /// /// Gets the special no-cache instance. @@ -63,7 +63,7 @@ namespace Umbraco.Core.Cache /// When used by repositories, all cache policies are bypassed. /// Used by repositories that do no cache. /// - public static CacheHelper NoCache { get; } = new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); + public static AppCaches NoCache { get; } = new AppCaches(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); /// /// Returns the current Request cache diff --git a/src/Umbraco.Core/Cache/CacheRefresherBase.cs b/src/Umbraco.Core/Cache/CacheRefresherBase.cs index 7242ab225e..5e6ec593af 100644 --- a/src/Umbraco.Core/Cache/CacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/CacheRefresherBase.cs @@ -16,10 +16,10 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance of the . /// - /// A cache helper. - protected CacheRefresherBase(CacheHelper cacheHelper) + /// A cache helper. + protected CacheRefresherBase(AppCaches appCaches) { - CacheHelper = cacheHelper; + AppCaches = appCaches; } /// @@ -93,7 +93,7 @@ namespace Umbraco.Core.Cache /// /// Gets the cache helper. /// - protected CacheHelper CacheHelper { get; } + protected AppCaches AppCaches { get; } /// /// Clears the cache for all repository entities of a specified type. @@ -102,7 +102,7 @@ namespace Umbraco.Core.Cache protected void ClearAllIsolatedCacheByEntityType() where TEntity : class, IEntity { - CacheHelper.IsolatedRuntimeCache.ClearCache(); + AppCaches.IsolatedRuntimeCache.ClearCache(); } /// diff --git a/src/Umbraco.Core/Cache/JsonCacheRefresherBase.cs b/src/Umbraco.Core/Cache/JsonCacheRefresherBase.cs index 27302f0786..d9d9644a36 100644 --- a/src/Umbraco.Core/Cache/JsonCacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/JsonCacheRefresherBase.cs @@ -13,8 +13,8 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance of the . /// - /// A cache helper. - protected JsonCacheRefresherBase(CacheHelper cacheHelper) : base(cacheHelper) + /// A cache helper. + protected JsonCacheRefresherBase(AppCaches appCaches) : base(appCaches) { } /// diff --git a/src/Umbraco.Core/Cache/PayloadCacheRefresherBase.cs b/src/Umbraco.Core/Cache/PayloadCacheRefresherBase.cs index 22bc46e020..4a3a03a0d6 100644 --- a/src/Umbraco.Core/Cache/PayloadCacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/PayloadCacheRefresherBase.cs @@ -15,8 +15,8 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance of the . /// - /// A cache helper. - protected PayloadCacheRefresherBase(CacheHelper cacheHelper) : base(cacheHelper) + /// A cache helper. + protected PayloadCacheRefresherBase(AppCaches appCaches) : base(appCaches) { } #region Json diff --git a/src/Umbraco.Core/Cache/TypedCacheRefresherBase.cs b/src/Umbraco.Core/Cache/TypedCacheRefresherBase.cs index 4defc15482..0b5a04b571 100644 --- a/src/Umbraco.Core/Cache/TypedCacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/TypedCacheRefresherBase.cs @@ -14,9 +14,9 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance of the . /// - /// A cache helper. - protected TypedCacheRefresherBase(CacheHelper cacheHelper) - : base(cacheHelper) + /// A cache helper. + protected TypedCacheRefresherBase(AppCaches appCaches) + : base(appCaches) { } #region Refresher diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 8c9ccd1088..9ed4a7265c 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -116,7 +116,7 @@ namespace Umbraco.Core.Composing.Composers return new LocalizedTextServiceFileSources( container.GetInstance(), - container.GetInstance().RuntimeCache, + container.GetInstance().RuntimeCache, mainLangFolder, pluginLangFolders.Concat(userLangFolders)); } diff --git a/src/Umbraco.Core/Composing/CompositionExtensions.cs b/src/Umbraco.Core/Composing/CompositionExtensions.cs index 2307d757c9..910062688c 100644 --- a/src/Umbraco.Core/Composing/CompositionExtensions.cs +++ b/src/Umbraco.Core/Composing/CompositionExtensions.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Composing public static void RegisterEssentials(this Composition composition, ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger, IMainDom mainDom, - CacheHelper appCaches, + AppCaches appCaches, IUmbracoDatabaseFactory databaseFactory, TypeLoader typeLoader, IRuntimeState state) @@ -28,7 +28,7 @@ namespace Umbraco.Core.Composing composition.RegisterUnique(profilingLogger); composition.RegisterUnique(mainDom); composition.RegisterUnique(appCaches); - composition.RegisterUnique(factory => factory.GetInstance().RuntimeCache); + composition.RegisterUnique(factory => factory.GetInstance().RuntimeCache); composition.RegisterUnique(databaseFactory); composition.RegisterUnique(factory => factory.GetInstance().SqlContext); composition.RegisterUnique(typeLoader); diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index 5c8351924f..bfc5cfd51c 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -180,8 +180,8 @@ namespace Umbraco.Core.Composing public static ICultureDictionaryFactory CultureDictionaryFactory => Factory.GetInstance(); - public static CacheHelper ApplicationCache - => Factory.GetInstance(); + public static AppCaches ApplicationCache + => Factory.GetInstance(); public static ServiceContext Services => Factory.GetInstance(); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs index 77759ea2da..1486935e2a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/AuditEntryRepository.cs @@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Initializes a new instance of the class. /// - public AuditEntryRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public AuditEntryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/AuditRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/AuditRepository.cs index 45f083bc6b..cda89fd89a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/AuditRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/AuditRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class AuditRepository : NPocoRepositoryBase, IAuditRepository { public AuditRepository(IScopeAccessor scopeAccessor, ILogger logger) - : base(scopeAccessor, CacheHelper.NoCache, logger) + : base(scopeAccessor, AppCaches.NoCache, logger) { } protected override void PersistNewItem(IAuditItem entity) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs index 3794bf183a..bd55654809 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Initializes a new instance of the class. /// - public ConsentRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public ConsentRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs index bd7943ff1d..ba56c17087 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement where TEntity : class, IUmbracoEntity where TRepository : class, IRepository { - protected ContentRepositoryBase(IScopeAccessor scopeAccessor, CacheHelper cache, ILanguageRepository languageRepository, ILogger logger) + protected ContentRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILanguageRepository languageRepository, ILogger logger) : base(scopeAccessor, cache, logger) { LanguageRepository = languageRepository; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs index 4bec3160a7..f608e2968d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly ITemplateRepository _templateRepository; - public ContentTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, ITemplateRepository templateRepository) + public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, ITemplateRepository templateRepository) : base(scopeAccessor, cache, logger) { _templateRepository = templateRepository; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 683df047f8..6404880a2e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -28,7 +28,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal abstract class ContentTypeRepositoryBase : NPocoRepositoryBase, IReadRepository where TEntity : class, IContentTypeComposition { - protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeContainerRepository.cs index f23b6df5e2..752b641bc3 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeContainerRepository.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { class DataTypeContainerRepository : EntityContainerRepository, IDataTypeContainerRepository { - public DataTypeContainerRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public DataTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.DataTypeContainer) { } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs index 4556c78fe6..28d4262763 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -27,7 +27,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly Lazy _editors; // fixme temp fixing circular dependencies with LAZY but is this the right place? - public DataTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, Lazy editors, ILogger logger) + public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger) : base(scopeAccessor, cache, logger) { _editors = editors; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs index 8f5ad70c32..3517fb3545 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class DictionaryRepository : NPocoRepositoryBase, IDictionaryRepository { - public DictionaryRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public DictionaryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } @@ -290,7 +290,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly DictionaryRepository _dictionaryRepository; - public DictionaryByUniqueIdRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public DictionaryByUniqueIdRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _dictionaryRepository = dictionaryRepository; @@ -343,7 +343,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly DictionaryRepository _dictionaryRepository; - public DictionaryByKeyRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public DictionaryByKeyRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _dictionaryRepository = dictionaryRepository; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs index 1d24cfd2dc..09fa420f26 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs @@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class DocumentBlueprintRepository : DocumentRepository, IDocumentBlueprintRepository { - public DocumentBlueprintRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IContentSection settings) - : base(scopeAccessor, cacheHelper, logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, settings) + public DocumentBlueprintRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IContentSection settings) + : base(scopeAccessor, appCaches, logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, settings) { EnsureUniqueNaming = false; // duplicates are allowed } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 054ab8cb4b..31c08f9124 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -25,20 +25,20 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IContentTypeRepository _contentTypeRepository; private readonly ITemplateRepository _templateRepository; private readonly ITagRepository _tagRepository; - private readonly CacheHelper _cacheHelper; + private readonly AppCaches _appCaches; private PermissionRepository _permissionRepository; private readonly ContentByGuidReadRepository _contentByGuidReadRepository; private readonly IScopeAccessor _scopeAccessor; - public DocumentRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IContentSection settings) - : base(scopeAccessor, cacheHelper, languageRepository, logger) + public DocumentRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IContentSection settings) + : base(scopeAccessor, appCaches, languageRepository, logger) { _contentTypeRepository = contentTypeRepository ?? throw new ArgumentNullException(nameof(contentTypeRepository)); _templateRepository = templateRepository ?? throw new ArgumentNullException(nameof(templateRepository)); _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); - _cacheHelper = cacheHelper; + _appCaches = appCaches; _scopeAccessor = scopeAccessor; - _contentByGuidReadRepository = new ContentByGuidReadRepository(this, scopeAccessor, cacheHelper, logger); + _contentByGuidReadRepository = new ContentByGuidReadRepository(this, scopeAccessor, appCaches, logger); EnsureUniqueNaming = settings.EnsureUniqueNaming; } @@ -48,7 +48,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // note: is ok to 'new' the repo here as it's a sub-repo really private PermissionRepository PermissionRepository => _permissionRepository - ?? (_permissionRepository = new PermissionRepository(_scopeAccessor, _cacheHelper, Logger)); + ?? (_permissionRepository = new PermissionRepository(_scopeAccessor, _appCaches, Logger)); #region Repository Base @@ -847,7 +847,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly DocumentRepository _outerRepo; - public ContentByGuidReadRepository(DocumentRepository outerRepo, IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public ContentByGuidReadRepository(DocumentRepository outerRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _outerRepo = outerRepo; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs index de8042cfcf..d50981e036 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { class DocumentTypeContainerRepository : EntityContainerRepository, IDocumentTypeContainerRepository { - public DocumentTypeContainerRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public DocumentTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.DocumentTypeContainer) { } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs index f75d82bd4e..fa06216f9b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class DomainRepository : NPocoRepositoryBase, IDomainRepository { - public DomainRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public DomainRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs index fae7ae2ebc..09fe949df1 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly Guid _containerObjectType; - public EntityContainerRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, Guid containerObjectType) + public EntityContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, Guid containerObjectType) : base(scopeAccessor, cache, logger) { var allowedContainers = new[] { Constants.ObjectTypes.DocumentTypeContainer, Constants.ObjectTypes.MediaTypeContainer, Constants.ObjectTypes.DataTypeContainer }; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ExternalLoginRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ExternalLoginRepository.cs index ce9a44f595..7cb78f4c9f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ExternalLoginRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ExternalLoginRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class ExternalLoginRepository : NPocoRepositoryBase, IExternalLoginRepository { - public ExternalLoginRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public ExternalLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index e236670e74..b3f2ff4af0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly Dictionary _codeIdMap = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _idCodeMap = new Dictionary(); - public LanguageRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public LanguageRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MacroRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MacroRepository.cs index 594f26fa72..565917e078 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MacroRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MacroRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class MacroRepository : NPocoRepositoryBase, IMacroRepository { - public MacroRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public MacroRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs index 3e665e321f..f2c7e35395 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly ITagRepository _tagRepository; private readonly MediaByGuidReadRepository _mediaByGuidReadRepository; - public MediaRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, IContentSection contentSection, ILanguageRepository languageRepository) + public MediaRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, IContentSection contentSection, ILanguageRepository languageRepository) : base(scopeAccessor, cache, languageRepository, logger) { _mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository)); @@ -395,7 +395,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly MediaRepository _outerRepo; - public MediaByGuidReadRepository(MediaRepository outerRepo, IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public MediaByGuidReadRepository(MediaRepository outerRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _outerRepo = outerRepo; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs index 318d3a9c5a..68b33e989d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { class MediaTypeContainerRepository : EntityContainerRepository, IMediaTypeContainerRepository { - public MediaTypeContainerRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public MediaTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.MediaTypeContainer) { } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs index 7dc1c29396..4639871a4a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class MediaTypeRepository : ContentTypeRepositoryBase, IMediaTypeRepository { - public MediaTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs index e80faaa44a..11166ce777 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class MemberGroupRepository : NPocoRepositoryBase, IMemberGroupRepository { - public MemberGroupRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public MemberGroupRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs index bfadebd61b..2daa4abeca 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly ITagRepository _tagRepository; private readonly IMemberGroupRepository _memberGroupRepository; - public MemberRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, ILanguageRepository languageRepository) + public MemberRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, ILanguageRepository languageRepository) : base(scopeAccessor, cache, languageRepository, logger) { _memberTypeRepository = memberTypeRepository ?? throw new ArgumentNullException(nameof(memberTypeRepository)); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs index 023e308ad3..b81ce4010b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class MemberTypeRepository : ContentTypeRepositoryBase, IMemberTypeRepository { - public MemberTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/NPocoRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/NPocoRepositoryBase.cs index df7517469c..234693602f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/NPocoRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/NPocoRepositoryBase.cs @@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Initializes a new instance of the class. /// - protected NPocoRepositoryBase(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + protected NPocoRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs index 8261ed2ea3..b4fd86c567 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/PermissionRepository.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class PermissionRepository : NPocoRepositoryBase where TEntity : class, IEntity { - public PermissionRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public PermissionRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs index f49905573d..bd2580b38f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class PublicAccessRepository : NPocoRepositoryBase, IPublicAccessRepository { - public PublicAccessRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public PublicAccessRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs index 3ca937ffcd..baac02b6bf 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RedirectUrlRepository.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class RedirectUrlRepository : NPocoRepositoryBase, IRedirectUrlRepository { - public RedirectUrlRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public RedirectUrlRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RelationRepository.cs index fb5ba00ea0..c5ba24f385 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RelationRepository.cs @@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IRelationTypeRepository _relationTypeRepository; public RelationRepository(IScopeAccessor scopeAccessor, ILogger logger, IRelationTypeRepository relationTypeRepository) - : base(scopeAccessor, CacheHelper.NoCache, logger) + : base(scopeAccessor, AppCaches.NoCache, logger) { _relationTypeRepository = relationTypeRepository; } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs index e4d8396e71..4faf78bd0a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class RelationTypeRepository : NPocoRepositoryBase, IRelationTypeRepository { - public RelationTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public RelationTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index 84c76dbb53..2626f60123 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private IRepositoryCachePolicy _cachePolicy; - protected RepositoryBase(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) { ScopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -28,7 +28,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected ILogger Logger { get; } - protected CacheHelper GlobalCache { get; } + protected AppCaches GlobalCache { get; } protected IRuntimeCacheProvider GlobalIsolatedCache => GlobalCache.IsolatedRuntimeCache.GetOrCreateCache(); @@ -127,7 +127,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { get { - if (GlobalCache == CacheHelper.NoCache) + if (GlobalCache == AppCaches.NoCache) return NoCacheRepositoryCachePolicy.Instance; // create the cache policy using IsolatedCache which is either global diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index 2679f8f92f..ead7c066be 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class ServerRegistrationRepository : NPocoRepositoryBase, IServerRegistrationRepository { public ServerRegistrationRepository(IScopeAccessor scopeAccessor, ILogger logger) - : base(scopeAccessor, CacheHelper.NoCache, logger) + : base(scopeAccessor, AppCaches.NoCache, logger) { } protected override IRepositoryCachePolicy CreateCachePolicy() diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/SimpleGetRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/SimpleGetRepository.cs index 7a3bfdb757..43233d0f31 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/SimpleGetRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/SimpleGetRepository.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement where TEntity : class, IEntity where TDto: class { - protected SimpleGetRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + protected SimpleGetRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs index 77e474be08..7dd3f03407 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/TagRepository.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class TagRepository : NPocoRepositoryBase, ITagRepository { - public TagRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public TagRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs index 19ef303ebe..bef71b1a51 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs @@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly ViewHelper _viewHelper; private readonly MasterPageHelper _masterPageHelper; - public TemplateRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, ITemplatesSection templateConfig, IFileSystems fileSystems) + public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, ITemplatesSection templateConfig, IFileSystems fileSystems) : base(scopeAccessor, cache, logger) { _masterpagesFileSystem = fileSystems.MasterPagesFileSystem; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs index 91466a0d09..c76a5de0d0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserGroupRepository.cs @@ -23,11 +23,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly UserGroupWithUsersRepository _userGroupWithUsersRepository; private readonly PermissionRepository _permissionRepository; - public UserGroupRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger) - : base(scopeAccessor, cacheHelper, logger) + public UserGroupRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger) + : base(scopeAccessor, appCaches, logger) { - _userGroupWithUsersRepository = new UserGroupWithUsersRepository(this, scopeAccessor, cacheHelper, logger); - _permissionRepository = new PermissionRepository(scopeAccessor, cacheHelper, logger); + _userGroupWithUsersRepository = new UserGroupWithUsersRepository(this, scopeAccessor, appCaches, logger); + _permissionRepository = new PermissionRepository(scopeAccessor, appCaches, logger); } public const string GetByAliasCacheKeyPrefix = "UserGroupRepository_GetByAlias_"; @@ -360,7 +360,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly UserGroupRepository _userGroupRepo; - public UserGroupWithUsersRepository(UserGroupRepository userGroupRepo, IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) + public UserGroupWithUsersRepository(UserGroupRepository userGroupRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _userGroupRepo = userGroupRepo; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs index 17fe79a55b..918cc66cb0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs @@ -35,22 +35,22 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// Constructor /// /// - /// + /// /// /// /// A dictionary specifying the configuration for user passwords. If this is null then no password configuration will be persisted or read. /// /// - public UserRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection, IGlobalSettings globalSettings) - : base(scopeAccessor, cacheHelper, logger) + public UserRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IMapperCollection mapperCollection, IGlobalSettings globalSettings) + : base(scopeAccessor, appCaches, logger) { _mapperCollection = mapperCollection; _globalSettings = globalSettings; } // for tests - internal UserRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection, IDictionary passwordConfig, IGlobalSettings globalSettings) - : base(scopeAccessor, cacheHelper, logger) + internal UserRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IMapperCollection mapperCollection, IDictionary passwordConfig, IGlobalSettings globalSettings) + : base(scopeAccessor, appCaches, logger) { _mapperCollection = mapperCollection; _globalSettings = globalSettings; diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 729e960896..f29109b9d2 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -325,13 +325,13 @@ namespace Umbraco.Core.Runtime /// /// Gets the application caches. /// - protected virtual CacheHelper GetAppCaches() + protected virtual AppCaches GetAppCaches() { // need the deep clone runtime cache provider to ensure entities are cached properly, ie // are cloned in and cloned out - no request-based cache here since no web-based context, // is overriden by the web runtime - return new CacheHelper( + return new AppCaches( new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), new StaticCacheProvider(), NullCacheProvider.Instance, diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 2236854351..79162c06ad 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -111,7 +111,7 @@ - + diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 984fb94fab..23e198b778 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Macros public void Setup() { //we DO want cache enabled for these tests - var cacheHelper = new CacheHelper( + var cacheHelper = new AppCaches( new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), NullCacheProvider.Instance, diff --git a/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs b/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs index 1f7c5624bf..f48abc1233 100644 --- a/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs @@ -20,7 +20,7 @@ namespace Umbraco.Tests.Models.Mapping base.Compose(); var manifestBuilder = new ManifestParser( - CacheHelper.Disabled.RuntimeCache, + AppCaches.Disabled.RuntimeCache, new ManifestValueValidatorCollection(Enumerable.Empty()), Composition.Logger) { diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index aeaf76967f..34699826ad 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -35,7 +35,7 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository) { - var cacheHelper = CacheHelper.Disabled; + var cacheHelper = AppCaches.Disabled; var templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(scopeAccessor, cacheHelper, Logger); contentTypeRepository = new ContentTypeRepository(scopeAccessor, cacheHelper, Logger, templateRepository); @@ -46,20 +46,20 @@ namespace Umbraco.Tests.Persistence.Repositories private ContentTypeRepository CreateRepository(IScopeAccessor scopeAccessor) { - var templateRepository = new TemplateRepository(scopeAccessor, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var contentTypeRepository = new ContentTypeRepository(scopeAccessor, CacheHelper.Disabled, Logger, templateRepository); + var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, templateRepository); return contentTypeRepository; } private MediaTypeRepository CreateMediaTypeRepository(IScopeAccessor scopeAccessor) { - var contentTypeRepository = new MediaTypeRepository(scopeAccessor, CacheHelper.Disabled, Logger); + var contentTypeRepository = new MediaTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); return contentTypeRepository; } private EntityContainerRepository CreateContainerRepository(IScopeAccessor scopeAccessor, Guid containerEntityType) { - return new EntityContainerRepository(scopeAccessor, CacheHelper.Disabled, Logger, containerEntityType); + return new EntityContainerRepository(scopeAccessor, AppCaches.Disabled, Logger, containerEntityType); } //TODO Add test to verify SetDefaultTemplates updates both AllowedTemplates and DefaultTemplate(id). @@ -71,7 +71,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var templateRepo = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepo = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); var repository = CreateRepository((IScopeAccessor) provider); var templates = new[] { diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index ce871d0d0a..b9724b0770 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -25,7 +25,7 @@ namespace Umbraco.Tests.Persistence.Repositories private EntityContainerRepository CreateContainerRepository(IScopeAccessor scopeAccessor) { - return new EntityContainerRepository(scopeAccessor, CacheHelper.Disabled, Logger, Constants.ObjectTypes.DataTypeContainer); + return new EntityContainerRepository(scopeAccessor, AppCaches.Disabled, Logger, Constants.ObjectTypes.DataTypeContainer); } [Test] diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index c1fa5381ff..772147f5ad 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -43,39 +43,39 @@ namespace Umbraco.Tests.Persistence.Repositories base.TearDown(); } - private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out DataTypeRepository dtdRepository, CacheHelper cacheHelper = null) + private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out DataTypeRepository dtdRepository, AppCaches appCaches = null) { - cacheHelper = cacheHelper ?? CacheHelper; + appCaches = appCaches ?? AppCaches; TemplateRepository tr; var ctRepository = CreateRepository(scopeAccessor, out contentTypeRepository, out tr); var editors = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - dtdRepository = new DataTypeRepository(scopeAccessor, cacheHelper, new Lazy(() => editors), Logger); + dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), Logger); return ctRepository; } - private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, CacheHelper cacheHelper = null) + private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, AppCaches appCaches = null) { TemplateRepository tr; - return CreateRepository(scopeAccessor, out contentTypeRepository, out tr, cacheHelper); + return CreateRepository(scopeAccessor, out contentTypeRepository, out tr, appCaches); } - private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository, CacheHelper cacheHelper = null) + private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository, AppCaches appCaches = null) { - cacheHelper = cacheHelper ?? CacheHelper; + appCaches = appCaches ?? AppCaches; - templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepository = new TagRepository(scopeAccessor, cacheHelper, Logger); - contentTypeRepository = new ContentTypeRepository(scopeAccessor, cacheHelper, Logger, templateRepository); - var languageRepository = new LanguageRepository(scopeAccessor, cacheHelper, Logger); - var repository = new DocumentRepository(scopeAccessor, cacheHelper, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger); + contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, Logger, templateRepository); + var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger); + var repository = new DocumentRepository(scopeAccessor, appCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); return repository; } [Test] public void CacheActiveForIntsAndGuids() { - var realCache = new CacheHelper( + var realCache = new AppCaches( new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider(), @@ -84,7 +84,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, cacheHelper: realCache); + var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, appCaches: realCache); var udb = (UmbracoDatabase)scope.Database; diff --git a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs index a5402f964e..a64a65047b 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs @@ -22,12 +22,12 @@ namespace Umbraco.Tests.Persistence.Repositories private DomainRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository, out DocumentRepository documentRepository, out LanguageRepository languageRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepository = new TagRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger); - contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger, templateRepository); - languageRepository = new LanguageRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger); - documentRepository = new DocumentRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); - var domainRepository = new DomainRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger); + var templateRepository = new TemplateRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepository = new TagRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); + contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, templateRepository); + languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); + documentRepository = new DocumentRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + var domainRepository = new DomainRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); return domainRepository; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs index 2f91c602af..5823537f7a 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Persistence.Repositories private LanguageRepository CreateRepository(IScopeProvider provider) { - return new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + return new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); } [Test] diff --git a/src/Umbraco.Tests/Persistence/Repositories/MacroRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MacroRepositoryTest.cs index e21debfdfd..6f215f4a35 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MacroRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MacroRepositoryTest.cs @@ -35,7 +35,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = new Macro("test1", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView); ; @@ -52,7 +52,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = repository.Get(1); macro.Alias = "test2"; @@ -69,7 +69,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Assert Assert.That(repository, Is.Not.Null); @@ -83,7 +83,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var macro = repository.Get(1); @@ -111,7 +111,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var macros = repository.GetMany(); @@ -129,7 +129,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var query = scope.SqlContext.Query().Where(x => x.Alias.ToUpper() == "TEST1"); @@ -147,7 +147,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var query = scope.SqlContext.Query().Where(x => x.Name.StartsWith("Test")); @@ -165,7 +165,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var macro = new Macro("test", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView); @@ -186,7 +186,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var macro = repository.Get(2); @@ -221,7 +221,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var macro = repository.Get(3); @@ -242,7 +242,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); // Act var exists = repository.Exists(3); @@ -261,7 +261,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = repository.Get(1); macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test")); @@ -287,7 +287,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = new Macro("newmacro", "A new macro", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView); macro.Properties.Add(new MacroProperty("blah1", "New1", 4, "test.editor")); @@ -312,7 +312,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = new Macro("newmacro", "A new macro", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView); macro.Properties.Add(new MacroProperty("blah1", "New1", 4, "test.editor")); @@ -336,7 +336,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = new Macro("newmacro", "A new macro", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView); var prop1 = new MacroProperty("blah1", "New1", 4, "test.editor"); @@ -367,7 +367,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = repository.Get(1); macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test")); @@ -394,7 +394,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var macro = repository.Get(1); macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test")); @@ -422,7 +422,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); repository.Save(new Macro("test1", "Test1", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView)); repository.Save(new Macro("test2", "Test2", "~/views/macropartials/test2.cshtml", MacroTypes.PartialView)); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index d1e7f96ff3..5e1900b29e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -30,14 +30,14 @@ namespace Umbraco.Tests.Persistence.Repositories CreateTestData(); } - private MediaRepository CreateRepository(IScopeProvider provider, out MediaTypeRepository mediaTypeRepository, CacheHelper cacheHelper = null) + private MediaRepository CreateRepository(IScopeProvider provider, out MediaTypeRepository mediaTypeRepository, AppCaches appCaches = null) { - cacheHelper = cacheHelper ?? CacheHelper; + appCaches = appCaches ?? AppCaches; var scopeAccessor = (IScopeAccessor) provider; - mediaTypeRepository = new MediaTypeRepository(scopeAccessor, cacheHelper, Logger); - var tagRepository = new TagRepository(scopeAccessor, cacheHelper, Logger); - var repository = new MediaRepository(scopeAccessor, cacheHelper, Logger, mediaTypeRepository, tagRepository, Mock.Of(), Mock.Of()); + mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, Logger); + var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger); + var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of(), Mock.Of()); return repository; } @@ -46,7 +46,7 @@ namespace Umbraco.Tests.Persistence.Repositories { MediaTypeRepository mediaTypeRepository; - var realCache = new CacheHelper( + var realCache = new AppCaches( new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider(), @@ -55,7 +55,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = CreateRepository(provider, out mediaTypeRepository, cacheHelper: realCache); + var repository = CreateRepository(provider, out mediaTypeRepository, appCaches: realCache); var udb = (UmbracoDatabase)scope.Database; diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs index ae4308db55..49bb93f2a7 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs @@ -21,12 +21,12 @@ namespace Umbraco.Tests.Persistence.Repositories { private MediaTypeRepository CreateRepository(IScopeProvider provider) { - return new MediaTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); + return new MediaTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); } private EntityContainerRepository CreateContainerRepository(IScopeProvider provider) { - return new EntityContainerRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Constants.ObjectTypes.MediaTypeContainer); + return new EntityContainerRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Constants.ObjectTypes.MediaTypeContainer); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index 18bfc4fcea..dea15cd4ad 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -29,10 +29,10 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberRepository CreateRepository(IScopeProvider provider, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository) { var accessor = (IScopeAccessor) provider; - memberTypeRepository = new MemberTypeRepository(accessor, CacheHelper.Disabled, Logger); - memberGroupRepository = new MemberGroupRepository(accessor, CacheHelper.Disabled, Logger); - var tagRepo = new TagRepository(accessor, CacheHelper.Disabled, Logger); - var repository = new MemberRepository(accessor, CacheHelper.Disabled, Logger, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of()); + memberTypeRepository = new MemberTypeRepository(accessor, AppCaches.Disabled, Logger); + memberGroupRepository = new MemberGroupRepository(accessor, AppCaches.Disabled, Logger); + var tagRepo = new TagRepository(accessor, AppCaches.Disabled, Logger); + var repository = new MemberRepository(accessor, AppCaches.Disabled, Logger, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of()); return repository; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs index 87d146f9f4..0c2314fd47 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs @@ -22,7 +22,7 @@ namespace Umbraco.Tests.Persistence.Repositories { private MemberTypeRepository CreateRepository(IScopeProvider provider) { - return new MemberTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + return new MemberTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); } [Test] diff --git a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs index e76d794e69..d28a002e31 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -59,7 +59,7 @@ namespace Umbraco.Tests.Persistence.Repositories using (var scope = provider.CreateScope()) { scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -99,7 +99,7 @@ namespace Umbraco.Tests.Persistence.Repositories using (var scope = provider.CreateScope()) { scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -144,7 +144,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -182,7 +182,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -210,7 +210,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var allEntries = new List(); for (int i = 0; i < 10; i++) @@ -274,7 +274,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, CacheHelper, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); var entry1 = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -307,11 +307,11 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, CacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepository = new TagRepository(accessor, CacheHelper, Logger); - contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper, Logger, templateRepository); - var languageRepository = new LanguageRepository(accessor, CacheHelper, Logger); - var repository = new DocumentRepository(accessor, CacheHelper, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + var templateRepository = new TemplateRepository(accessor, AppCaches, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepository = new TagRepository(accessor, AppCaches, Logger); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, templateRepository); + var languageRepository = new LanguageRepository(accessor, AppCaches, Logger); + var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); return repository; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs b/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs index ca2c713a27..66f6655c77 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs @@ -188,7 +188,7 @@ namespace Umbraco.Tests.Persistence.Repositories private IRedirectUrlRepository CreateRepository(IScopeProvider provider) { - return new RedirectUrlRepository((IScopeAccessor) provider, CacheHelper, Logger); + return new RedirectUrlRepository((IScopeAccessor) provider, AppCaches, Logger); } private IContent _textpage, _subpage, _otherpage, _trashed; diff --git a/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs index 697951d021..cea7f44b71 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs @@ -30,7 +30,7 @@ namespace Umbraco.Tests.Persistence.Repositories private RelationRepository CreateRepository(IScopeProvider provider, out RelationTypeRepository relationTypeRepository) { var accessor = (IScopeAccessor) provider; - relationTypeRepository = new RelationTypeRepository(accessor, CacheHelper.Disabled, Mock.Of()); + relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of()); var repository = new RelationRepository(accessor, Mock.Of(), relationTypeRepository); return repository; } @@ -266,7 +266,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var relationTypeRepository = new RelationTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var relationTypeRepository = new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); var relationRepository = new RelationRepository((IScopeAccessor) provider, Mock.Of(), relationTypeRepository); relationTypeRepository.Save(relateContent); diff --git a/src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs index 26b2fe48c2..e52e2dfcdf 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Persistence.Repositories private RelationTypeRepository CreateRepository(IScopeProvider provider) { - return new RelationTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + return new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); } @@ -232,7 +232,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = ScopeProvider.CreateScope()) { - var repository = new RelationTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); repository.Save(relateContent);//Id 2 repository.Save(relateContentType);//Id 3 diff --git a/src/Umbraco.Tests/Persistence/Repositories/ServerRegistrationRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ServerRegistrationRepositoryTest.cs index 08c34f453c..e2fc4b4705 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ServerRegistrationRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ServerRegistrationRepositoryTest.cs @@ -16,13 +16,13 @@ namespace Umbraco.Tests.Persistence.Repositories [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class ServerRegistrationRepositoryTest : TestWithDatabaseBase { - private CacheHelper _cacheHelper; + private AppCaches _appCaches; public override void SetUp() { base.SetUp(); - _cacheHelper = new CacheHelper(); + _appCaches = new AppCaches(); CreateTestData(); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs index 78eb736007..4812131a61 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs @@ -947,26 +947,26 @@ namespace Umbraco.Tests.Persistence.Repositories private TagRepository CreateRepository(IScopeProvider provider) { - return new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); + return new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); } private DocumentRepository CreateContentRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepository = new TagRepository(accessor, CacheHelper.Disabled, Logger); - contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper.Disabled, Logger, templateRepository); - var languageRepository = new LanguageRepository(accessor, CacheHelper.Disabled, Logger); - var repository = new DocumentRepository(accessor, CacheHelper.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, templateRepository); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger); + var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); return repository; } private MediaRepository CreateMediaRepository(IScopeProvider provider, out MediaTypeRepository mediaTypeRepository) { var accessor = (IScopeAccessor) provider; - var tagRepository = new TagRepository(accessor, CacheHelper.Disabled, Logger); - mediaTypeRepository = new MediaTypeRepository(accessor, CacheHelper.Disabled, Logger); - var repository = new MediaRepository(accessor, CacheHelper.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of(), Mock.Of()); + var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); + mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, Logger); + var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of(), Mock.Of()); return repository; } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs index f4bed68315..94471aed7e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Persistence.Repositories private ITemplateRepository CreateRepository(IScopeProvider provider, ITemplatesSection templatesSection = null) { - return new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, + return new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, templatesSection ?? Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc), _fileSystems); } @@ -363,10 +363,10 @@ namespace Umbraco.Tests.Persistence.Repositories { var templateRepository = CreateRepository(ScopeProvider); - var tagRepository = new TagRepository((IScopeAccessor) ScopeProvider, CacheHelper.Disabled, Logger); - var contentTypeRepository = new ContentTypeRepository((IScopeAccessor) ScopeProvider, CacheHelper.Disabled, Logger, templateRepository); - var languageRepository = new LanguageRepository((IScopeAccessor) ScopeProvider, CacheHelper.Disabled, Logger); - var contentRepo = new DocumentRepository((IScopeAccessor) ScopeProvider, CacheHelper.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + var tagRepository = new TagRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger); + var contentTypeRepository = new ContentTypeRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, templateRepository); + var languageRepository = new LanguageRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger); + var contentRepo = new DocumentRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage"); ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs index f0fb8cff88..311372ef10 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs @@ -19,7 +19,7 @@ namespace Umbraco.Tests.Persistence.Repositories { private UserGroupRepository CreateRepository(IScopeProvider provider) { - return new UserGroupRepository((IScopeAccessor) provider, Core.Cache.CacheHelper.Disabled, Mock.Of()); + return new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, Mock.Of()); } [Test] @@ -131,7 +131,7 @@ namespace Umbraco.Tests.Persistence.Repositories var id = userGroup.Id; - var repository2 = new UserGroupRepository((IScopeAccessor) provider, Core.Cache.CacheHelper.Disabled, Logger); + var repository2 = new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, Logger); repository2.Delete(userGroup); scope.Complete(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 847972cc50..7934544d8f 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -26,9 +26,9 @@ namespace Umbraco.Tests.Persistence.Repositories private MediaRepository CreateMediaRepository(IScopeProvider provider, out IMediaTypeRepository mediaTypeRepository) { var accessor = (IScopeAccessor) provider; - mediaTypeRepository = new MediaTypeRepository(accessor, CacheHelper, Mock.Of()); - var tagRepository = new TagRepository(accessor, CacheHelper, Mock.Of()); - var repository = new MediaRepository(accessor, CacheHelper, Mock.Of(), mediaTypeRepository, tagRepository, Mock.Of(), Mock.Of()); + mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches, Mock.Of()); + var tagRepository = new TagRepository(accessor, AppCaches, Mock.Of()); + var repository = new MediaRepository(accessor, AppCaches, Mock.Of(), mediaTypeRepository, tagRepository, Mock.Of(), Mock.Of()); return repository; } @@ -41,25 +41,25 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateContentRepository(IScopeProvider provider, out IContentTypeRepository contentTypeRepository, out ITemplateRepository templateRepository) { var accessor = (IScopeAccessor) provider; - templateRepository = new TemplateRepository(accessor, CacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepository = new TagRepository(accessor, CacheHelper, Logger); - contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper, Logger, templateRepository); - var languageRepository = new LanguageRepository(accessor, CacheHelper, Logger); - var repository = new DocumentRepository(accessor, CacheHelper, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + templateRepository = new TemplateRepository(accessor, AppCaches, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepository = new TagRepository(accessor, AppCaches, Logger); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, templateRepository); + var languageRepository = new LanguageRepository(accessor, AppCaches, Logger); + var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); return repository; } private UserRepository CreateRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - var repository = new UserRepository(accessor, CacheHelper.Disabled, Logger, Mappers, TestObjects.GetGlobalSettings()); + var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, TestObjects.GetGlobalSettings()); return repository; } private UserGroupRepository CreateUserGroupRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - return new UserGroupRepository(accessor, CacheHelper.Disabled, Logger); + return new UserGroupRepository(accessor, AppCaches.Disabled, Logger); } [Test] @@ -207,7 +207,7 @@ namespace Umbraco.Tests.Persistence.Repositories var id = user.Id; - var repository2 = new UserRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(),TestObjects.GetGlobalSettings()); + var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(),TestObjects.GetGlobalSettings()); repository2.Delete(user); diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 84f4f5dbd7..fe2cbdc145 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -173,7 +173,7 @@ namespace Umbraco.Tests.Routing /// public class CustomDocumentController : RenderMvcController { - public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(globalSettings, umbracoContext, services, applicationCache, logger, profilingLogger) { } diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs index ccb7427907..3a52eea17c 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -59,7 +59,7 @@ namespace Umbraco.Tests.Runtimes var logger = new ConsoleLogger(); var profiler = new LogProfiler(logger); var profilingLogger = new ProfilingLogger(logger, profiler); - var appCaches = new CacheHelper(); // fixme has HttpRuntime stuff? + var appCaches = new AppCaches(); // fixme has HttpRuntime stuff? var databaseFactory = new UmbracoDatabaseFactory(logger, new Lazy(() => factory.GetInstance())); var typeLoader = new TypeLoader(appCaches.RuntimeCache, LocalTempStorage.Default, profilingLogger); var mainDom = new SimpleMainDom(); @@ -239,7 +239,7 @@ namespace Umbraco.Tests.Runtimes var logger = new ConsoleLogger(); var profiler = Mock.Of(); var profilingLogger = new ProfilingLogger(logger, profiler); - var appCaches = CacheHelper.Disabled; + var appCaches = AppCaches.Disabled; var databaseFactory = Mock.Of(); var typeLoader = new TypeLoader(appCaches.RuntimeCache, LocalTempStorage.Default, profilingLogger); var runtimeState = Mock.Of(); diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index 3a0cb00ea9..5d4fa4f182 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -37,10 +37,10 @@ namespace Umbraco.Tests.Scoping .Add(() => Composition.TypeLoader.GetCacheRefreshers()); } - protected override CacheHelper GetCacheHelper() + protected override AppCaches GetCacheHelper() { // this is what's created core web runtime - return new CacheHelper( + return new AppCaches( new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), new StaticCacheProvider(), NullCacheProvider.Instance, diff --git a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs index 3aefa88a50..c56f66fc94 100644 --- a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs @@ -163,11 +163,11 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); - var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var repository = new DocumentRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository); + var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); // Act Stopwatch watch = Stopwatch.StartNew(); @@ -196,11 +196,11 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); - var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var repository = new DocumentRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository); + var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); // Act Stopwatch watch = Stopwatch.StartNew(); @@ -227,11 +227,11 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); - var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var repository = new DocumentRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository); + var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); // Act var contents = repository.GetMany(); @@ -261,11 +261,11 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); - var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); - var repository = new DocumentRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository); + var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, Mock.Of()); // Act var contents = repository.GetMany(); diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 0f48a9c99a..799ce6a47c 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -3037,11 +3037,11 @@ namespace Umbraco.Tests.Services private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); - var tagRepository = new TagRepository(accessor, CacheHelper.Disabled, Logger); - contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper.Disabled, Logger, templateRepository); - var languageRepository = new LanguageRepository(accessor, CacheHelper.Disabled, Logger); - var repository = new DocumentRepository(accessor, CacheHelper.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); + var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, templateRepository); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger); + var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, Mock.Of()); return repository; } } diff --git a/src/Umbraco.Tests/Services/MacroServiceTests.cs b/src/Umbraco.Tests/Services/MacroServiceTests.cs index 52cc8ab0d1..69e816585e 100644 --- a/src/Umbraco.Tests/Services/MacroServiceTests.cs +++ b/src/Umbraco.Tests/Services/MacroServiceTests.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, CacheHelper.Disabled, Mock.Of()); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of()); repository.Save(new Macro("test1", "Test1", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView)); repository.Save(new Macro("test2", "Test2", "~/views/macropartials/test2.cshtml", MacroTypes.PartialView)); diff --git a/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs b/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs index 795d79ced1..ececf46a18 100644 --- a/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs +++ b/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs @@ -15,7 +15,7 @@ namespace Umbraco.Tests.Templates [TestFixture] public class TemplateRepositoryTests { - private readonly Mock _cacheMock = new Mock(); + private readonly Mock _cacheMock = new Mock(); private readonly Mock _templateConfigMock = new Mock(); private readonly IFileSystems _fileSystems = Mock.Of(); private TemplateRepository _templateRepository; diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 9e2a2156ee..94e38d6872 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -151,7 +151,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting urlHelper.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(UrlInfo.Url("/hello/world/1234")); - var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbCtx), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()); + var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbCtx), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()); var umbHelper = new UmbracoHelper(umbCtx, Mock.Of(), diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 14ffeb743f..29eb649c48 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -90,7 +90,7 @@ namespace Umbraco.Tests.TestHelpers /// just mock the services to be passed to the ctor of the ServiceContext. public ServiceContext GetServiceContext( IScopeProvider scopeProvider, IScopeAccessor scopeAccessor, - CacheHelper cache, + AppCaches cache, ILogger logger, IGlobalSettings globalSettings, IUmbracoSettingsSection umbracoSettings, diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index c413cb0e94..575f14e818 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -56,7 +56,7 @@ namespace Umbraco.Tests.Testing.TestingTests Composition.Register(_ => Mock.Of()); Composition.Register(_ => Mock.Of()); Composition.Register(_ => Mock.Of()); - Composition.Register(_ => CacheHelper.Disabled); + Composition.Register(_ => AppCaches.Disabled); Composition.Register(); // ReSharper disable once UnusedVariable @@ -65,7 +65,7 @@ namespace Umbraco.Tests.Testing.TestingTests Mock.Of(), Mock.Of(), Mock.Of(), - new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()), + new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()), ServiceContext.CreatePartial()); Assert.Pass(); } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index a79531af74..c980f9c1ee 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -101,7 +101,7 @@ namespace Umbraco.Tests.Testing protected virtual IProfilingLogger ProfilingLogger => Factory.GetInstance(); - protected CacheHelper CacheHelper => Factory.GetInstance(); + protected AppCaches AppCaches => Factory.GetInstance(); protected virtual ISqlSyntaxProvider SqlSyntax => Factory.GetInstance(); @@ -199,9 +199,9 @@ namespace Umbraco.Tests.Testing return (logger, profiler); } - protected virtual CacheHelper GetCacheHelper() + protected virtual AppCaches GetCacheHelper() { - return CacheHelper.Disabled; + return AppCaches.Disabled; } protected virtual void ComposeWeb() diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 35e8f0a937..03844b5d72 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -132,7 +132,7 @@ namespace Umbraco.Tests.Web.Mvc Mock.Of(), Mock.Of(), Mock.Of(), - new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()), + new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()), ServiceContext.CreatePartial()); var ctrl = new TestSurfaceController(umbracoContext, helper); @@ -185,7 +185,7 @@ namespace Umbraco.Tests.Web.Mvc public class TestSurfaceController : SurfaceController { public TestSurfaceController(UmbracoContext ctx, UmbracoHelper helper = null) - : base(ctx, null, ServiceContext.CreatePartial(), Mock.Of(), null, null) + : base(ctx, null, ServiceContext.CreatePartial(), Mock.Of(), null, null) { if (helper != null) { diff --git a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs index c1ab217642..cf93b44215 100644 --- a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs @@ -5,8 +5,8 @@ namespace Umbraco.Web.Cache { public sealed class ApplicationCacheRefresher : CacheRefresherBase { - public ApplicationCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public ApplicationCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -25,7 +25,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); base.RefreshAll(); } @@ -37,7 +37,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs index 247c33c361..72fceec631 100644 --- a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs @@ -5,8 +5,8 @@ namespace Umbraco.Web.Cache { public sealed class ApplicationTreeCacheRefresher : CacheRefresherBase { - public ApplicationTreeCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public ApplicationTreeCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -25,7 +25,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); base.RefreshAll(); } @@ -37,7 +37,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - CacheHelper.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs index b0192e9e75..3ae2f8e3dd 100644 --- a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs @@ -20,8 +20,8 @@ namespace Umbraco.Web.Cache private readonly IdkMap _idkMap; private readonly IDomainService _domainService; - public ContentCacheRefresher(CacheHelper cacheHelper, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap, IDomainService domainService) - : base(cacheHelper) + public ContentCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap, IDomainService domainService) + : base(appCaches) { _publishedSnapshotService = publishedSnapshotService; _idkMap = idkMap; @@ -44,10 +44,10 @@ namespace Umbraco.Web.Cache public override void Refresh(JsonPayload[] payloads) { - CacheHelper.RuntimeCache.ClearCacheObjectTypes(); + AppCaches.RuntimeCache.ClearCacheObjectTypes(); var idsRemoved = new HashSet(); - var isolatedCache = CacheHelper.IsolatedRuntimeCache.GetOrCreateCache(); + var isolatedCache = AppCaches.IsolatedRuntimeCache.GetOrCreateCache(); foreach (var payload in payloads) { @@ -103,7 +103,7 @@ namespace Umbraco.Web.Cache { // when a public version changes Current.ApplicationCache.ClearPartialViewCache(); - MacroCacheRefresher.ClearMacroContentCache(CacheHelper); // just the content + MacroCacheRefresher.ClearMacroContentCache(AppCaches); // just the content } base.Refresh(payloads); @@ -153,17 +153,17 @@ namespace Umbraco.Web.Cache #region Indirect - public static void RefreshContentTypes(CacheHelper cacheHelper) + public static void RefreshContentTypes(AppCaches appCaches) { // we could try to have a mechanism to notify the PublishedCachesService // and figure out whether published items were modified or not... keep it // simple for now, just clear the whole thing - cacheHelper.ClearPartialViewCache(); - MacroCacheRefresher.ClearMacroContentCache(cacheHelper); // just the content + appCaches.ClearPartialViewCache(); + MacroCacheRefresher.ClearMacroContentCache(appCaches); // just the content - cacheHelper.IsolatedRuntimeCache.ClearCache(); - cacheHelper.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedRuntimeCache.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs index c1b99d25ec..90b6e79ae1 100644 --- a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs @@ -13,8 +13,8 @@ namespace Umbraco.Web.Cache private readonly IPublishedSnapshotService _publishedSnapshotService; private readonly IdkMap _idkMap; - public ContentTypeCacheRefresher(CacheHelper cacheHelper, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap) - : base(cacheHelper) + public ContentTypeCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap) + : base(appCaches) { _publishedSnapshotService = publishedSnapshotService; _idkMap = idkMap; @@ -65,15 +65,15 @@ namespace Umbraco.Web.Cache if (payloads.Any(x => x.ItemType == typeof(IContentType).Name)) // don't try to be clever - refresh all - ContentCacheRefresher.RefreshContentTypes(CacheHelper); + ContentCacheRefresher.RefreshContentTypes(AppCaches); if (payloads.Any(x => x.ItemType == typeof(IMediaType).Name)) // don't try to be clever - refresh all - MediaCacheRefresher.RefreshMediaTypes(CacheHelper); + MediaCacheRefresher.RefreshMediaTypes(AppCaches); if (payloads.Any(x => x.ItemType == typeof(IMemberType).Name)) // don't try to be clever - refresh all - MemberCacheRefresher.RefreshMemberTypes(CacheHelper); + MemberCacheRefresher.RefreshMemberTypes(AppCaches); // notify _publishedSnapshotService.Notify(payloads); diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index be17c28067..e1a8f05e39 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -15,8 +15,8 @@ namespace Umbraco.Web.Cache private readonly IPublishedSnapshotService _publishedSnapshotService; private readonly IdkMap _idkMap; - public DataTypeCacheRefresher(CacheHelper cacheHelper, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap) - : base(cacheHelper) + public DataTypeCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap) + : base(appCaches) { _publishedSnapshotService = publishedSnapshotService; _idkMap = idkMap; @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache ClearAllIsolatedCacheByEntityType(); ClearAllIsolatedCacheByEntityType(); - var dataTypeCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var dataTypeCache = AppCaches.IsolatedRuntimeCache.GetCache(); foreach (var payload in payloads) { diff --git a/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs b/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs index 7dadee87b1..525b4d2157 100644 --- a/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs @@ -6,8 +6,8 @@ namespace Umbraco.Web.Cache { public sealed class DictionaryCacheRefresher : CacheRefresherBase { - public DictionaryCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public DictionaryCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define diff --git a/src/Umbraco.Web/Cache/DomainCacheRefresher.cs b/src/Umbraco.Web/Cache/DomainCacheRefresher.cs index 6907a654ff..37b0a483a6 100644 --- a/src/Umbraco.Web/Cache/DomainCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DomainCacheRefresher.cs @@ -10,8 +10,8 @@ namespace Umbraco.Web.Cache { private readonly IPublishedSnapshotService _publishedSnapshotService; - public DomainCacheRefresher(CacheHelper cacheHelper, IPublishedSnapshotService publishedSnapshotService) - : base(cacheHelper) + public DomainCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService) + : base(appCaches) { _publishedSnapshotService = publishedSnapshotService; } diff --git a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs index bee12020cb..f5fe5075eb 100644 --- a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs @@ -10,8 +10,8 @@ namespace Umbraco.Web.Cache { public sealed class LanguageCacheRefresher : CacheRefresherBase { - public LanguageCacheRefresher(CacheHelper cacheHelper, IPublishedSnapshotService publishedSnapshotService, IDomainService domainService) - : base(cacheHelper) + public LanguageCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IDomainService domainService) + : base(appCaches) { _publishedSnapshotService = publishedSnapshotService; _domainService = domainService; diff --git a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs index a4af601379..cdeb2ffdd0 100644 --- a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs @@ -12,8 +12,8 @@ namespace Umbraco.Web.Cache { public sealed class MacroCacheRefresher : JsonCacheRefresherBase { - public MacroCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public MacroCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -33,11 +33,11 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { foreach (var prefix in GetAllMacroCacheKeys()) - CacheHelper.RuntimeCache.ClearCacheByKeySearch(prefix); + AppCaches.RuntimeCache.ClearCacheByKeySearch(prefix); ClearAllIsolatedCacheByEntityType(); - CacheHelper.RuntimeCache.ClearCacheObjectTypes(); + AppCaches.RuntimeCache.ClearCacheObjectTypes(); base.RefreshAll(); } @@ -49,9 +49,9 @@ namespace Umbraco.Web.Cache foreach (var payload in payloads) { foreach (var alias in GetCacheKeysForAlias(payload.Alias)) - CacheHelper.RuntimeCache.ClearCacheByKeySearch(alias); + AppCaches.RuntimeCache.ClearCacheByKeySearch(alias); - var macroRepoCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var macroRepoCache = AppCaches.IsolatedRuntimeCache.GetCache(); if (macroRepoCache) { macroRepoCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(payload.Id)); @@ -110,9 +110,9 @@ namespace Umbraco.Web.Cache return GetAllMacroCacheKeys().Select(x => x + alias).ToArray(); } - public static void ClearMacroContentCache(CacheHelper cacheHelper) + public static void ClearMacroContentCache(AppCaches appCaches) { - cacheHelper.RuntimeCache.ClearCacheObjectTypes(); + appCaches.RuntimeCache.ClearCacheObjectTypes(); } #endregion diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index 4abf7d8787..a6ccd7e005 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -18,8 +18,8 @@ namespace Umbraco.Web.Cache private readonly IPublishedSnapshotService _publishedSnapshotService; private readonly IdkMap _idkMap; - public MediaCacheRefresher(CacheHelper cacheHelper, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap) - : base(cacheHelper) + public MediaCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap) + : base(appCaches) { _publishedSnapshotService = publishedSnapshotService; _idkMap = idkMap; @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache { Current.ApplicationCache.ClearPartialViewCache(); - var mediaCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var mediaCache = AppCaches.IsolatedRuntimeCache.GetCache(); foreach (var payload in payloads) { @@ -119,9 +119,9 @@ namespace Umbraco.Web.Cache #region Indirect - public static void RefreshMediaTypes(CacheHelper cacheHelper) + public static void RefreshMediaTypes(AppCaches appCaches) { - cacheHelper.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedRuntimeCache.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs index 237daa39b4..29c102e7a2 100644 --- a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs @@ -11,8 +11,8 @@ namespace Umbraco.Web.Cache { private readonly IdkMap _idkMap; - public MemberCacheRefresher(CacheHelper cacheHelper, IdkMap idkMap) - : base(cacheHelper) + public MemberCacheRefresher(AppCaches appCaches, IdkMap idkMap) + : base(appCaches) { _idkMap = idkMap; } @@ -58,9 +58,9 @@ namespace Umbraco.Web.Cache private void ClearCache(int id) { _idkMap.ClearCache(id); - CacheHelper.ClearPartialViewCache(); + AppCaches.ClearPartialViewCache(); - var memberCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var memberCache = AppCaches.IsolatedRuntimeCache.GetCache(); if (memberCache) memberCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); } @@ -69,9 +69,9 @@ namespace Umbraco.Web.Cache #region Indirect - public static void RefreshMemberTypes(CacheHelper cacheHelper) + public static void RefreshMemberTypes(AppCaches appCaches) { - cacheHelper.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedRuntimeCache.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs index 4540f0b495..9368b0f9f4 100644 --- a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs @@ -8,8 +8,8 @@ namespace Umbraco.Web.Cache { public sealed class MemberGroupCacheRefresher : JsonCacheRefresherBase { - public MemberGroupCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public MemberGroupCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache // Since we cache by group name, it could be problematic when renaming to // previously existing names - see http://issues.umbraco.org/issue/U4-10846. // To work around this, just clear all the cache items - CacheHelper.IsolatedRuntimeCache.ClearCache(); + AppCaches.IsolatedRuntimeCache.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs b/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs index 7c3af1129f..59c8231ed2 100644 --- a/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs @@ -6,8 +6,8 @@ namespace Umbraco.Web.Cache { public sealed class PublicAccessCacheRefresher : CacheRefresherBase { - public PublicAccessCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public PublicAccessCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define diff --git a/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs index 4dd7282f98..8b1c8581cd 100644 --- a/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs @@ -8,8 +8,8 @@ namespace Umbraco.Web.Cache { public sealed class RelationTypeCacheRefresher : CacheRefresherBase { - public RelationTypeCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public RelationTypeCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -34,7 +34,7 @@ namespace Umbraco.Web.Cache public override void Refresh(int id) { - var cache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var cache = AppCaches.IsolatedRuntimeCache.GetCache(); if (cache) cache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); base.Refresh(id); } @@ -47,7 +47,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - var cache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var cache = AppCaches.IsolatedRuntimeCache.GetCache(); if (cache) cache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs index 6f76d148cc..7ff7c6fdb6 100644 --- a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs @@ -9,8 +9,8 @@ namespace Umbraco.Web.Cache { private readonly IdkMap _idkMap; - public TemplateCacheRefresher(CacheHelper cacheHelper, IdkMap idkMap) - : base(cacheHelper) + public TemplateCacheRefresher(AppCaches appCaches, IdkMap idkMap) + : base(appCaches) { _idkMap = idkMap; } @@ -52,7 +52,7 @@ namespace Umbraco.Web.Cache private void RemoveFromCache(int id) { _idkMap.ClearCache(id); - CacheHelper.RuntimeCache.ClearCacheItem($"{CacheKeys.TemplateFrontEndCacheKey}{id}"); + AppCaches.RuntimeCache.ClearCacheItem($"{CacheKeys.TemplateFrontEndCacheKey}{id}"); //need to clear the runtime cache for templates ClearAllIsolatedCacheByEntityType(); diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index ae57fc902a..a502a7554f 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -8,8 +8,8 @@ namespace Umbraco.Web.Cache { public sealed class UserCacheRefresher : CacheRefresherBase { - public UserCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public UserCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -40,7 +40,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - var userCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var userCache = AppCaches.IsolatedRuntimeCache.GetCache(); if (userCache) userCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); diff --git a/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs index deb49ad624..4dea595c85 100644 --- a/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs @@ -14,8 +14,8 @@ namespace Umbraco.Web.Cache /// public sealed class UserGroupCacheRefresher : CacheRefresherBase { - public UserGroupCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public UserGroupCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define @@ -35,7 +35,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { ClearAllIsolatedCacheByEntityType(); - var userGroupCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var userGroupCache = AppCaches.IsolatedRuntimeCache.GetCache(); if (userGroupCache) { userGroupCache.Result.ClearCacheByKeySearch(UserGroupRepository.GetByAliasCacheKeyPrefix); @@ -55,7 +55,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - var userGroupCache = CacheHelper.IsolatedRuntimeCache.GetCache(); + var userGroupCache = AppCaches.IsolatedRuntimeCache.GetCache(); if (userGroupCache) { userGroupCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); diff --git a/src/Umbraco.Web/Cache/UserGroupPermissionsCacheRefresher.cs b/src/Umbraco.Web/Cache/UserGroupPermissionsCacheRefresher.cs index bd2ad50ef5..37e02a0149 100644 --- a/src/Umbraco.Web/Cache/UserGroupPermissionsCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserGroupPermissionsCacheRefresher.cs @@ -8,8 +8,8 @@ namespace Umbraco.Web.Cache [EditorBrowsable(EditorBrowsableState.Never)] public sealed class UserGroupPermissionsCacheRefresher : CacheRefresherBase { - public UserGroupPermissionsCacheRefresher(CacheHelper cacheHelper) - : base(cacheHelper) + public UserGroupPermissionsCacheRefresher(AppCaches appCaches) + : base(appCaches) { } #region Define diff --git a/src/Umbraco.Web/CacheHelperExtensions.cs b/src/Umbraco.Web/CacheHelperExtensions.cs index d7aa838a09..3c5ea1930d 100644 --- a/src/Umbraco.Web/CacheHelperExtensions.cs +++ b/src/Umbraco.Web/CacheHelperExtensions.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web /// /// Outputs and caches a partial view in MVC /// - /// + /// /// /// /// @@ -28,7 +28,7 @@ namespace Umbraco.Web /// /// public static IHtmlString CachedPartialView( - this CacheHelper cacheHelper, + this AppCaches appCaches, HtmlHelper htmlHelper, string partialViewName, object model, @@ -43,7 +43,7 @@ namespace Umbraco.Web return htmlHelper.Partial(partialViewName, model, viewData); } - return cacheHelper.RuntimeCache.GetCacheItem( + return appCaches.RuntimeCache.GetCacheItem( PartialViewCacheKey + cacheKey, () => htmlHelper.Partial(partialViewName, model, viewData), priority: CacheItemPriority.NotRemovable, //not removable, the same as macros (apparently issue #27610) @@ -53,10 +53,10 @@ namespace Umbraco.Web /// /// Clears the cache for partial views /// - /// - public static void ClearPartialViewCache(this CacheHelper cacheHelper) + /// + public static void ClearPartialViewCache(this AppCaches appCaches) { - cacheHelper.RuntimeCache.ClearCacheByKeySearch(PartialViewCacheKey); + appCaches.RuntimeCache.ClearCacheByKeySearch(PartialViewCacheKey); } } } diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 1e8f3d17f7..ed1853c351 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -203,7 +203,7 @@ namespace Umbraco.Web.Composing public static IProfilingLogger ProfilingLogger => CoreCurrent.ProfilingLogger; - public static CacheHelper ApplicationCache => CoreCurrent.ApplicationCache; + public static AppCaches ApplicationCache => CoreCurrent.ApplicationCache; public static ServiceContext Services => CoreCurrent.Services; diff --git a/src/Umbraco.Web/Controllers/UmbLoginController.cs b/src/Umbraco.Web/Controllers/UmbLoginController.cs index fc6613200c..684925c3e3 100644 --- a/src/Umbraco.Web/Controllers/UmbLoginController.cs +++ b/src/Umbraco.Web/Controllers/UmbLoginController.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.Controllers { } - public UmbLoginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + public UmbLoginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) { } diff --git a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs b/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs index 83f4ae04a1..3f394824f6 100644 --- a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs +++ b/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.Controllers { } - public UmbLoginStatusController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) + public UmbLoginStatusController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) { } diff --git a/src/Umbraco.Web/Controllers/UmbProfileController.cs b/src/Umbraco.Web/Controllers/UmbProfileController.cs index 7ee8385edc..459d1b1829 100644 --- a/src/Umbraco.Web/Controllers/UmbProfileController.cs +++ b/src/Umbraco.Web/Controllers/UmbProfileController.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.Controllers { } - public UmbProfileController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) + public UmbProfileController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) { } diff --git a/src/Umbraco.Web/Controllers/UmbRegisterController.cs b/src/Umbraco.Web/Controllers/UmbRegisterController.cs index 5a5024dad9..0288995b1f 100644 --- a/src/Umbraco.Web/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web/Controllers/UmbRegisterController.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.Controllers { } - public UmbRegisterController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) + public UmbRegisterController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) { } diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 231ec9ba67..d1c9ec48bb 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.Editors /// /// Initializes a new instance of the class with all its dependencies. /// - public AuthenticationController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + public AuthenticationController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 6294a0377f..414c248041 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -49,7 +49,7 @@ namespace Umbraco.Web.Editors private const string TokenPasswordResetCode = "PasswordResetCode"; private static readonly string[] TempDataTokenNames = { TokenExternalSignInError, TokenPasswordResetCode }; - public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger, IRuntimeState runtimeState) + public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, services, applicationCache, logger, profilingLogger) { _manifestParser = manifestParser; diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 670d37e7a7..84ce177eef 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.Editors IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, PropertyEditorCollection propertyEditors, - ServiceContext services, CacheHelper applicationCache, + ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs index 898208319a..8d23a34c5e 100644 --- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.Editors private readonly ICultureDictionaryFactory _cultureDictionaryFactory; private ICultureDictionary _cultureDictionary; - protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { _cultureDictionaryFactory = cultureDictionaryFactory; } diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web/Editors/DashboardController.cs index 8960f110c3..3fdf1b78c8 100644 --- a/src/Umbraco.Web/Editors/DashboardController.cs +++ b/src/Umbraco.Web/Editors/DashboardController.cs @@ -38,7 +38,7 @@ namespace Umbraco.Web.Editors /// /// Initializes a new instance of the with all its dependencies. /// - public DashboardController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards) + public DashboardController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { _dashboards = dashboards; diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index f2b8fd3dda..b8617e6f94 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -37,7 +37,7 @@ namespace Umbraco.Web.Editors [MediaTypeControllerControllerConfiguration] public class MediaTypeController : ContentTypeControllerBase { - public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/Editors/MemberTypeController.cs b/src/Umbraco.Web/Editors/MemberTypeController.cs index 3abc0035d3..4ba5204e4d 100644 --- a/src/Umbraco.Web/Editors/MemberTypeController.cs +++ b/src/Umbraco.Web/Editors/MemberTypeController.cs @@ -30,7 +30,7 @@ namespace Umbraco.Web.Editors [UmbracoTreeAuthorize(new string[] { Constants.Trees.MemberTypes, Constants.Trees.Members})] public class MemberTypeController : ContentTypeControllerBase { - public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(cultureDictionaryFactory, globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 05d1e2a7a3..f59fd360ed 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -45,7 +45,7 @@ namespace Umbraco.Web.Editors public class PackageInstallController : UmbracoAuthorizedJsonController { public PackageInstallController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, - ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, + ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { diff --git a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs index 3baa5e85ff..8cb9408044 100644 --- a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs +++ b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs @@ -37,7 +37,7 @@ namespace Umbraco.Web.Editors /// /// /// - protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) + protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } } diff --git a/src/Umbraco.Web/Mvc/PluginController.cs b/src/Umbraco.Web/Mvc/PluginController.cs index a8d73fe575..a8e7f1f0d1 100644 --- a/src/Umbraco.Web/Mvc/PluginController.cs +++ b/src/Umbraco.Web/Mvc/PluginController.cs @@ -50,7 +50,7 @@ namespace Umbraco.Web.Mvc /// /// Gets or sets the application cache. /// - public CacheHelper ApplicationCache { get; } + public AppCaches ApplicationCache { get; } /// /// Gets or sets the logger. @@ -93,14 +93,14 @@ namespace Umbraco.Web.Mvc Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance(), + Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance() ) { } - protected PluginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + protected PluginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) { UmbracoContext = umbracoContext; DatabaseFactory = databaseFactory; diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index 44a6a9346d..dc775450bf 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Mvc ActionInvoker = new RenderActionInvoker(); } - public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(globalSettings, umbracoContext, services, applicationCache, logger, profilingLogger) { ActionInvoker = new RenderActionInvoker(); diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs index b3e67e4b2b..1035d43739 100644 --- a/src/Umbraco.Web/Mvc/SurfaceController.cs +++ b/src/Umbraco.Web/Mvc/SurfaceController.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.Mvc { } - protected SurfaceController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + protected SurfaceController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(umbracoContext, databaseFactory, services, applicationCache, logger, profilingLogger) { } diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs index 2f8f7a6e76..7084b79271 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.Mvc protected UmbracoAuthorizedController() { } - protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) : base(globalSettings, umbracoContext, services, applicationCache, logger, profilingLogger) { } } diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs index 36f688b714..7d451321bc 100644 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoController.cs @@ -48,7 +48,7 @@ namespace Umbraco.Web.Mvc /// /// Gets or sets the application cache. /// - public CacheHelper ApplicationCache { get; set; } + public AppCaches ApplicationCache { get; set; } /// /// Gets or sets the logger. @@ -83,14 +83,14 @@ namespace Umbraco.Web.Mvc Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance(), + Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance() ) { } - protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, CacheHelper applicationCache, ILogger logger, IProfilingLogger profilingLogger) + protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches applicationCache, ILogger logger, IProfilingLogger profilingLogger) { GlobalSettings = globalSettings; UmbracoContext = umbracoContext; diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs index 394aa39dd9..2c5c0395a4 100644 --- a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs +++ b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs @@ -39,7 +39,7 @@ namespace Umbraco.Web.Mvc /// /// Gets or sets the application cache. /// - public CacheHelper ApplicationCache { get; set; } + public AppCaches ApplicationCache { get; set; } // fixme // previously, Services and ApplicationCache would derive from UmbracoContext.Application, which @@ -110,12 +110,12 @@ namespace Umbraco.Web.Mvc protected UmbracoViewPage() : this( Current.Factory.GetInstance(), - Current.Factory.GetInstance() + Current.Factory.GetInstance() ) { } - protected UmbracoViewPage(ServiceContext services, CacheHelper applicationCache) + protected UmbracoViewPage(ServiceContext services, AppCaches applicationCache) { Services = services; ApplicationCache = applicationCache; diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Web/Runtime/WebRuntime.cs index ad1a4851f0..c69a3bec8b 100644 --- a/src/Umbraco.Web/Runtime/WebRuntime.cs +++ b/src/Umbraco.Web/Runtime/WebRuntime.cs @@ -59,7 +59,7 @@ namespace Umbraco.Web.Runtime protected override IProfiler GetProfiler() => _webProfiler; - protected override CacheHelper GetAppCaches() => new CacheHelper( + protected override AppCaches GetAppCaches() => new AppCaches( // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) new DeepCloneRuntimeCacheProvider(new HttpRuntimeCacheProvider(HttpRuntime.Cache)), diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index eb4c24aabc..6ae8ff8c96 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.Security private readonly IUserService _userService; private readonly IPublicAccessService _publicAccessService; private readonly PublishedRouter _publishedRouter; - private readonly CacheHelper _appCaches; + private readonly AppCaches _appCaches; private readonly ILogger _logger; #region Constructors @@ -47,7 +47,7 @@ namespace Umbraco.Web.Security IUserService userService, IPublicAccessService publicAccessService, PublishedRouter publishedRouter, - CacheHelper appCaches, + AppCaches appCaches, ILogger logger ) { diff --git a/src/Umbraco.Web/Services/ApplicationTreeService.cs b/src/Umbraco.Web/Services/ApplicationTreeService.cs index 86bfc5d0bb..2ddec054c7 100644 --- a/src/Umbraco.Web/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Web/Services/ApplicationTreeService.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.Services internal class ApplicationTreeService : IApplicationTreeService { private readonly ILogger _logger; - private readonly CacheHelper _cache; + private readonly AppCaches _cache; private readonly TypeLoader _typeLoader; private Lazy> _allAvailableTrees; internal const string TreeConfigFileName = "trees.config"; @@ -27,7 +27,7 @@ namespace Umbraco.Web.Services private static readonly object Locker = new object(); private readonly Lazy>> _groupedTrees; - public ApplicationTreeService(ILogger logger, CacheHelper cache, TypeLoader typeLoader) + public ApplicationTreeService(ILogger logger, AppCaches cache, TypeLoader typeLoader) { _logger = logger; _cache = cache; diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index 6337db67f9..2d06141292 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.Services private readonly Lazy> _allAvailableSections; private readonly IApplicationTreeService _applicationTreeService; private readonly IScopeProvider _scopeProvider; - private readonly CacheHelper _cache; + private readonly AppCaches _cache; internal const string AppConfigFileName = "applications.config"; private static string _appConfig; private static readonly object Locker = new object(); @@ -32,7 +32,7 @@ namespace Umbraco.Web.Services IUserService userService, IApplicationTreeService applicationTreeService, IScopeProvider scopeProvider, - CacheHelper cache) + AppCaches cache) { _applicationTreeService = applicationTreeService ?? throw new ArgumentNullException(nameof(applicationTreeService)); _cache = cache ?? throw new ArgumentNullException(nameof(cache)); diff --git a/src/Umbraco.Web/TagsController.cs b/src/Umbraco.Web/TagsController.cs index 181b9f7da2..784f1d9883 100644 --- a/src/Umbraco.Web/TagsController.cs +++ b/src/Umbraco.Web/TagsController.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.WebServices /// /// Initializes a new instance of the with all its dependencies. /// - public TagsController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + public TagsController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index 3db3610cc2..a779632def 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.WebApi /// /// Initialize a new instance of the with all its dependencies. /// - protected UmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + protected UmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs index 21b88cc919..44457fbef1 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs @@ -39,7 +39,7 @@ namespace Umbraco.Web.WebApi Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance(), + Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance() ) @@ -48,7 +48,7 @@ namespace Umbraco.Web.WebApi /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoApiControllerBase(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + protected UmbracoApiControllerBase(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) { GlobalSettings = globalSettings; _umbracoContextAccessor = umbracoContextAccessor; @@ -88,7 +88,7 @@ namespace Umbraco.Web.WebApi /// /// Gets the application cache. /// - public CacheHelper ApplicationCache { get; } + public AppCaches ApplicationCache { get; } /// /// Gets the logger. diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 4ae9c00a47..1d20857efd 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -40,7 +40,7 @@ namespace Umbraco.Web.WebApi /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) + protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches applicationCache, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { } From 1667e914cd4354f9edcb45cedeaf0d4b3108faad Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Jan 2019 18:38:55 +1100 Subject: [PATCH 154/223] Allows the tree collection to be manipulated by devs on startup, renames some things --- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 13 +++++-------- src/Umbraco.Web/Services/ITreeService.cs | 8 ++++---- src/Umbraco.Web/Services/TreeService.cs | 8 ++++---- .../Trees/ApplicationTreeController.cs | 2 +- .../Trees/BackOfficeSectionCollectionBuilder.cs | 9 ++------- src/Umbraco.Web/Trees/ITree.cs | 3 ++- src/Umbraco.Web/Trees/Tree.cs | 2 +- src/Umbraco.Web/Trees/TreeCollectionBuilder.cs | 15 +++++++-------- 8 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index f21c040a37..1a0bf8d1b0 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -1,15 +1,13 @@ -using System.Web; +using System.Linq; +using System.Web; using System.Web.Security; using Examine; using Microsoft.AspNet.SignalR; using Umbraco.Core; using Umbraco.Core.Components; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; -using Umbraco.Core.Models; -using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -23,9 +21,7 @@ using Umbraco.Web.Dictionary; using Umbraco.Web.Editors; using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; -using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.PublishedContent; -using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -207,12 +203,13 @@ namespace Umbraco.Web.Runtime .Append(); // register back office trees - foreach (var treeControllerType in umbracoApiControllerTypes) + foreach (var treeControllerType in umbracoApiControllerTypes + .Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))) { var attribute = treeControllerType.GetCustomAttribute(false); if (attribute == null) continue; var tree = new Tree(attribute.SortOrder, attribute.ApplicationAlias, attribute.TreeAlias, attribute.TreeTitle, treeControllerType, attribute.IsSingleNodeTree); - composition.WithCollectionBuilder().AddTree(tree); + composition.WithCollectionBuilder().Trees.Add(tree); } } } diff --git a/src/Umbraco.Web/Services/ITreeService.cs b/src/Umbraco.Web/Services/ITreeService.cs index 5172e4b7b7..96787086c6 100644 --- a/src/Umbraco.Web/Services/ITreeService.cs +++ b/src/Umbraco.Web/Services/ITreeService.cs @@ -26,16 +26,16 @@ namespace Umbraco.Web.Services /// /// Gets the application tree for the applcation with the specified alias /// - /// The application alias. + /// The application alias. /// Returns a ApplicationTree Array - IEnumerable GetApplicationTrees(string applicationAlias); + IEnumerable GetTrees(string sectionAlias); /// /// Gets the grouped application trees for the application with the specified alias /// - /// + /// /// - IDictionary> GetGroupedApplicationTrees(string applicationAlias); + IDictionary> GetGroupedTrees(string sectionAlias); } } diff --git a/src/Umbraco.Web/Services/TreeService.cs b/src/Umbraco.Web/Services/TreeService.cs index 8389c27a19..f58dce59bc 100644 --- a/src/Umbraco.Web/Services/TreeService.cs +++ b/src/Umbraco.Web/Services/TreeService.cs @@ -24,13 +24,13 @@ namespace Umbraco.Web.Services public IEnumerable GetAll() => _treeCollection; /// - public IEnumerable GetApplicationTrees(string applicationAlias) - => GetAll().Where(x => x.ApplicationAlias.InvariantEquals(applicationAlias)).OrderBy(x => x.SortOrder).ToList(); + public IEnumerable GetTrees(string sectionAlias) + => GetAll().Where(x => x.ApplicationAlias.InvariantEquals(sectionAlias)).OrderBy(x => x.SortOrder).ToList(); - public IDictionary> GetGroupedApplicationTrees(string applicationAlias) + public IDictionary> GetGroupedTrees(string sectionAlias) { var result = new Dictionary>(); - var foundTrees = GetApplicationTrees(applicationAlias).ToList(); + var foundTrees = GetTrees(sectionAlias).ToList(); foreach(var treeGroup in _groupedTrees.Value) { List resultGroup = null; diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 5a0f72c8dc..5433f3c157 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -60,7 +60,7 @@ namespace Umbraco.Web.Trees if (string.IsNullOrEmpty(application)) throw new HttpResponseException(HttpStatusCode.NotFound); //find all tree definitions that have the current application alias - var groupedTrees = _treeService.GetGroupedApplicationTrees(application); + var groupedTrees = _treeService.GetGroupedTrees(application); var allTrees = groupedTrees.Values.SelectMany(x => x).ToList(); if (string.IsNullOrEmpty(tree) == false || allTrees.Count == 1) diff --git a/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs b/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs index ec5833f79c..3228cd309f 100644 --- a/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs +++ b/src/Umbraco.Web/Trees/BackOfficeSectionCollectionBuilder.cs @@ -12,12 +12,6 @@ namespace Umbraco.Web.Trees { protected override BackOfficeSectionCollectionBuilder This => this; - // need to inject dependencies in the collection, so override creation - public override BackOfficeSectionCollection CreateCollection(IFactory factory) - { - return new BackOfficeSectionCollection(CreateItems(factory)); - } - protected override IEnumerable CreateItems(IFactory factory) { // get the manifest parser just-in-time - injecting it in the ctor would mean that @@ -25,7 +19,8 @@ namespace Umbraco.Web.Trees // its dependencies too, and that can create cycles or other oddities var manifestParser = factory.GetInstance(); - return base.CreateItems(factory).Concat(manifestParser.Manifest.Sections.Select(x => new ManifestBackOfficeSection(x.Key, x.Value))); + return base.CreateItems(factory) + .Concat(manifestParser.Manifest.Sections.Select(x => new ManifestBackOfficeSection(x.Key, x.Value))); } private class ManifestBackOfficeSection : IBackOfficeSection diff --git a/src/Umbraco.Web/Trees/ITree.cs b/src/Umbraco.Web/Trees/ITree.cs index f408ce5e60..867beda20e 100644 --- a/src/Umbraco.Web/Trees/ITree.cs +++ b/src/Umbraco.Web/Trees/ITree.cs @@ -1,7 +1,8 @@ namespace Umbraco.Web.Trees { //fixme - we don't really use this, it is nice to have the treecontroller, attribute and ApplicationTree streamlined to implement this but it's not used - public interface ITree + //leave as internal for now, maybe we'll use in the future, means we could pass around ITree + internal interface ITree { /// /// Gets or sets the sort order. diff --git a/src/Umbraco.Web/Trees/Tree.cs b/src/Umbraco.Web/Trees/Tree.cs index 3bac5bae58..39f5cec1eb 100644 --- a/src/Umbraco.Web/Trees/Tree.cs +++ b/src/Umbraco.Web/Trees/Tree.cs @@ -43,7 +43,7 @@ namespace Umbraco.Web.Trees public Type TreeControllerType { get; } - public static string GetRootNodeDisplayName(ITree tree, ILocalizedTextService textService) + internal static string GetRootNodeDisplayName(ITree tree, ILocalizedTextService textService) { var label = $"[{tree.TreeAlias}]"; diff --git a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs index 143b8e308b..ae2675bac9 100644 --- a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs +++ b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs @@ -3,16 +3,15 @@ using Umbraco.Core.Composing; namespace Umbraco.Web.Trees { - //fixme - how will we allow users to modify these items? they will need to be able to change the ApplicationTree's registered (i.e. sort order, section) - public class TreeCollectionBuilder : CollectionBuilderBase + public class TreeCollectionBuilder : ICollectionBuilder { - private readonly List _instances = new List(); + /// + /// expose the list of trees which developers can manipulate before the collection is created + /// + public List Trees { get; } = new List(); - public void AddTree(Tree tree) - { - _instances.Add(tree); - } + public TreeCollection CreateCollection(IFactory factory) => new TreeCollection(Trees); - protected override IEnumerable CreateItems(IFactory factory) => _instances; + public void RegisterWith(IRegister register) => register.Register(CreateCollection, Lifetime.Singleton); } } From 0bee01e0eeea61ba2861a9e3b16f3594ea9a9396 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 17 Jan 2019 11:01:23 +0100 Subject: [PATCH 155/223] Great AppCaches renaming --- src/Umbraco.Core/Cache/AppCaches.cs | 75 +++-- .../Cache/AppPolicedCacheDictionary.cs | 74 +++++ .../Cache/CacheProviderExtensions.cs | 24 +- src/Umbraco.Core/Cache/CacheRefresherBase.cs | 2 +- src/Umbraco.Core/Cache/DeepCloneAppCache.cs | 157 ++++++++++ .../Cache/DeepCloneRuntimeCacheProvider.cs | 155 ---------- .../Cache/DefaultRepositoryCachePolicy.cs | 30 +- .../Cache/DictionaryCacheProvider.cs | 178 ++++------- ...rBase.cs => FastDictionaryAppCacheBase.cs} | 242 ++++++++------- .../Cache/FastDictionaryCacheProvider.cs | 162 ++++++++++ .../Cache/FullDataSetRepositoryCachePolicy.cs | 8 +- ...acheProvider.cs => HttpRequestAppCache.cs} | 157 +++++----- src/Umbraco.Core/Cache/IAppCache.cs | 94 ++++++ src/Umbraco.Core/Cache/IAppPolicedCache.cs | 54 ++++ src/Umbraco.Core/Cache/ICacheProvider.cs | 68 ----- .../Cache/IRuntimeCacheProvider.cs | 35 --- src/Umbraco.Core/Cache/IsolatedCaches.cs | 41 +++ .../Cache/IsolatedRuntimeCache.cs | 91 ------ src/Umbraco.Core/Cache/NoAppCache.cs | 82 +++++ .../Cache/NoCacheRepositoryCachePolicy.cs | 2 +- src/Umbraco.Core/Cache/NullCacheProvider.cs | 66 ---- ...acheProvider.cs => ObjectCacheAppCache.cs} | 283 +++++++++--------- .../Cache/RepositoryCachePolicyBase.cs | 10 +- .../SingleItemsOnlyRepositoryCachePolicy.cs | 2 +- src/Umbraco.Core/Cache/StaticCacheProvider.cs | 79 ----- ...CacheProvider.cs => WebCachingAppCache.cs} | 118 +++----- src/Umbraco.Core/Composing/TypeLoader.cs | 8 +- src/Umbraco.Core/ConfigsExtensions.cs | 2 +- .../Configuration/Grid/GridConfig.cs | 2 +- .../Configuration/Grid/GridEditorsConfig.cs | 4 +- src/Umbraco.Core/Manifest/ManifestParser.cs | 6 +- src/Umbraco.Core/Models/UserExtensions.cs | 2 +- .../Implement/ConsentRepository.cs | 2 +- .../Implement/DictionaryRepository.cs | 12 +- .../Implement/RepositoryBaseOfTIdTEntity.cs | 12 +- src/Umbraco.Core/Runtime/CoreRuntime.cs | 8 +- src/Umbraco.Core/Scoping/IScope.cs | 2 +- src/Umbraco.Core/Scoping/Scope.cs | 10 +- .../LocalizedTextServiceFileSources.cs | 6 +- src/Umbraco.Core/Umbraco.Core.csproj | 23 +- src/Umbraco.Tests/Cache/CacheProviderTests.cs | 94 +++--- .../DeepCloneRuntimeCacheProviderTests.cs | 16 +- .../Cache/DefaultCachePolicyTests.cs | 26 +- .../Cache/FullDataSetCachePolicyTests.cs | 32 +- .../Cache/HttpRequestCacheProviderTests.cs | 14 +- .../Cache/HttpRuntimeCacheProviderTests.cs | 16 +- .../Cache/ObjectCacheProviderTests.cs | 8 +- .../PublishedContentCacheTests.cs | 2 +- .../PublishedMediaCacheTests.cs | 8 +- .../Cache/RuntimeCacheProviderTests.cs | 4 +- .../Cache/SingleItemsOnlyCachePolicyTests.cs | 10 +- .../Composing/ComposingTestBase.cs | 2 +- .../Composing/TypeLoaderTests.cs | 2 +- src/Umbraco.Tests/CoreThings/UdiTests.cs | 2 +- .../FrontEnd/UmbracoHelperTests.cs | 2 +- src/Umbraco.Tests/Macros/MacroTests.cs | 8 +- .../Manifest/ManifestParserTests.cs | 2 +- src/Umbraco.Tests/Models/ContentTests.cs | 6 +- .../Repositories/DocumentRepositoryTest.cs | 8 +- .../Repositories/MediaRepositoryTest.cs | 8 +- .../Published/PropertyCacheLevelTests.cs | 4 +- .../PublishedContentSnapshotTestBase.cs | 2 +- .../PublishedContent/PublishedContentTests.cs | 2 +- .../PublishedContent/PublishedMediaTests.cs | 20 +- .../SolidPublishedSnapshot.cs | 4 +- .../Scoping/ScopedRepositoryTests.cs | 54 ++-- .../TestHelpers/BaseUsingSqlCeSyntax.cs | 2 +- .../TestHelpers/TestWithDatabaseBase.cs | 2 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 6 +- .../Web/Mvc/UmbracoViewPageTests.cs | 2 +- .../Web/TemplateUtilitiesTests.cs | 2 +- .../Cache/ApplicationCacheRefresher.cs | 4 +- .../Cache/ApplicationTreeCacheRefresher.cs | 4 +- .../Cache/ContentCacheRefresher.cs | 12 +- .../Cache/DataTypeCacheRefresher.cs | 2 +- src/Umbraco.Web/Cache/MacroCacheRefresher.cs | 12 +- src/Umbraco.Web/Cache/MediaCacheRefresher.cs | 8 +- src/Umbraco.Web/Cache/MemberCacheRefresher.cs | 6 +- .../Cache/MemberGroupCacheRefresher.cs | 2 +- .../Cache/RelationTypeCacheRefresher.cs | 8 +- .../Cache/TemplateCacheRefresher.cs | 2 +- src/Umbraco.Web/Cache/UserCacheRefresher.cs | 4 +- .../Cache/UserGroupCacheRefresher.cs | 10 +- src/Umbraco.Web/CacheHelperExtensions.cs | 2 +- .../Dictionary/UmbracoCultureDictionary.cs | 6 +- .../Editors/ExamineManagementController.cs | 10 +- src/Umbraco.Web/Editors/UsersController.cs | 2 +- src/Umbraco.Web/Macros/MacroRenderer.cs | 2 +- .../Models/Mapping/UserMapperProfile.cs | 2 +- .../PublishedCache/IPublishedSnapshot.cs | 4 +- .../PublishedCache/NuCache/ContentCache.cs | 8 +- .../PublishedCache/NuCache/MediaCache.cs | 8 +- .../PublishedCache/NuCache/MemberCache.cs | 4 +- .../PublishedCache/NuCache/Property.cs | 6 +- .../NuCache/PublishedContent.cs | 10 +- .../NuCache/PublishedSnapshot.cs | 8 +- .../NuCache/PublishedSnapshotService.cs | 8 +- .../PublishedElementPropertyBase.cs | 6 +- .../DictionaryPublishedContent.cs | 4 +- .../PublishedContentCache.cs | 6 +- .../XmlPublishedCache/PublishedMediaCache.cs | 12 +- .../XmlPublishedCache/PublishedMemberCache.cs | 4 +- .../XmlPublishedCache/PublishedSnapshot.cs | 4 +- .../PublishedSnapshotService.cs | 6 +- .../XmlPublishedCache/XmlPublishedContent.cs | 10 +- src/Umbraco.Web/Runtime/WebRuntime.cs | 10 +- .../Services/ApplicationTreeService.cs | 2 +- src/Umbraco.Web/Services/SectionService.cs | 2 +- 108 files changed, 1538 insertions(+), 1440 deletions(-) create mode 100644 src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs create mode 100644 src/Umbraco.Core/Cache/DeepCloneAppCache.cs delete mode 100644 src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs rename src/Umbraco.Core/Cache/{DictionaryCacheProviderBase.cs => FastDictionaryAppCacheBase.cs} (81%) create mode 100644 src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs rename src/Umbraco.Core/Cache/{HttpRequestCacheProvider.cs => HttpRequestAppCache.cs} (53%) create mode 100644 src/Umbraco.Core/Cache/IAppCache.cs create mode 100644 src/Umbraco.Core/Cache/IAppPolicedCache.cs delete mode 100644 src/Umbraco.Core/Cache/ICacheProvider.cs delete mode 100644 src/Umbraco.Core/Cache/IRuntimeCacheProvider.cs create mode 100644 src/Umbraco.Core/Cache/IsolatedCaches.cs delete mode 100644 src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs create mode 100644 src/Umbraco.Core/Cache/NoAppCache.cs delete mode 100644 src/Umbraco.Core/Cache/NullCacheProvider.cs rename src/Umbraco.Core/Cache/{ObjectCacheRuntimeCacheProvider.cs => ObjectCacheAppCache.cs} (73%) delete mode 100644 src/Umbraco.Core/Cache/StaticCacheProvider.cs rename src/Umbraco.Core/Cache/{HttpRuntimeCacheProvider.cs => WebCachingAppCache.cs} (68%) diff --git a/src/Umbraco.Core/Cache/AppCaches.cs b/src/Umbraco.Core/Cache/AppCaches.cs index 7dd95624ef..6372bccbab 100644 --- a/src/Umbraco.Core/Cache/AppCaches.cs +++ b/src/Umbraco.Core/Cache/AppCaches.cs @@ -4,47 +4,41 @@ using System.Web; namespace Umbraco.Core.Cache { /// - /// Represents the application-wide caches. + /// Represents the application caches. /// public class AppCaches { /// - /// Initializes a new instance for use in the web + /// Initializes a new instance of the for use in a web application. /// public AppCaches() - : this( - new HttpRuntimeCacheProvider(HttpRuntime.Cache), - new StaticCacheProvider(), - new HttpRequestCacheProvider(), - new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) - { - } + : this(HttpRuntime.Cache) + { } /// - /// Initializes a new instance for use in the web + /// Initializes a new instance of the for use in a web application. /// public AppCaches(System.Web.Caching.Cache cache) : this( - new HttpRuntimeCacheProvider(cache), - new StaticCacheProvider(), - new HttpRequestCacheProvider(), - new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) - { - } + new WebCachingAppCache(cache), + new DictionaryCacheProvider(), + new HttpRequestAppCache(), + new IsolatedCaches(t => new ObjectCacheAppCache())) + { } /// - /// Initializes a new instance based on the provided providers + /// Initializes a new instance of the with cache providers. /// public AppCaches( - IRuntimeCacheProvider httpCacheProvider, - ICacheProvider staticCacheProvider, - ICacheProvider requestCacheProvider, - IsolatedRuntimeCache isolatedCacheManager) + IAppPolicedCache runtimeCache, + IAppCache staticCacheProvider, + IAppCache requestCache, + IsolatedCaches isolatedCaches) { - RuntimeCache = httpCacheProvider ?? throw new ArgumentNullException(nameof(httpCacheProvider)); + RuntimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); StaticCache = staticCacheProvider ?? throw new ArgumentNullException(nameof(staticCacheProvider)); - RequestCache = requestCacheProvider ?? throw new ArgumentNullException(nameof(requestCacheProvider)); - IsolatedRuntimeCache = isolatedCacheManager ?? throw new ArgumentNullException(nameof(isolatedCacheManager)); + RequestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache)); + IsolatedCaches = isolatedCaches ?? throw new ArgumentNullException(nameof(isolatedCaches)); } /// @@ -54,7 +48,7 @@ namespace Umbraco.Core.Cache /// When used by repositories, all cache policies apply, but the underlying caches do not cache anything. /// Used by tests. /// - public static AppCaches Disabled { get; } = new AppCaches(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); + public static AppCaches Disabled { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(_ => NoAppCache.Instance)); /// /// Gets the special no-cache instance. @@ -63,27 +57,42 @@ namespace Umbraco.Core.Cache /// When used by repositories, all cache policies are bypassed. /// Used by repositories that do no cache. /// - public static AppCaches NoCache { get; } = new AppCaches(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); + public static AppCaches NoCache { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(_ => NoAppCache.Instance)); /// - /// Returns the current Request cache + /// Gets the per-request cache. /// - public ICacheProvider RequestCache { get; internal set; } + /// + /// The per-request caches works on top of the current HttpContext items. + /// fixme - what about non-web applications? + /// + public IAppCache RequestCache { get; } /// /// Returns the current Runtime cache /// - public ICacheProvider StaticCache { get; internal set; } + /// + /// fixme - what is this? why not use RuntimeCache? + /// + public IAppCache StaticCache { get; } /// - /// Returns the current Runtime cache + /// Gets the runtime cache. /// - public IRuntimeCacheProvider RuntimeCache { get; internal set; } + /// + /// The runtime cache is the main application cache. + /// + public IAppPolicedCache RuntimeCache { get; } /// - /// Returns the current Isolated Runtime cache manager + /// Gets the isolated caches. /// - public IsolatedRuntimeCache IsolatedRuntimeCache { get; internal set; } + /// + /// Isolated caches are used by e.g. repositories, to ensure that each cached entity + /// type has its own cache, so that lookups are fast and the repository does not need to + /// search through all keys on a global scale. + /// + public IsolatedCaches IsolatedCaches { get; } } diff --git a/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs b/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs new file mode 100644 index 0000000000..51cc3c4c53 --- /dev/null +++ b/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Concurrent; + +namespace Umbraco.Core.Cache +{ + /// + /// Provides a base class for implementing a dictionary of . + /// + /// The type of the dictionary key. + public abstract class AppPolicedCacheDictionary + { + private readonly ConcurrentDictionary _caches = new ConcurrentDictionary(); + + /// + /// Initializes a new instance of the class. + /// + /// + protected AppPolicedCacheDictionary(Func cacheFactory) + { + CacheFactory = cacheFactory; + } + + /// + /// Gets the internal cache factory, for tests only! + /// + internal readonly Func CacheFactory; + + /// + /// Gets or creates a cache. + /// + public IAppPolicedCache GetOrCreate(TKey key) + => _caches.GetOrAdd(key, k => CacheFactory(k)); + + /// + /// Tries to get a cache. + /// + public Attempt Get(TKey key) + => _caches.TryGetValue(key, out var cache) ? Attempt.Succeed(cache) : Attempt.Fail(); + + /// + /// Removes a cache. + /// + public void Remove(TKey key) + { + _caches.TryRemove(key, out _); + } + + /// + /// Removes all caches. + /// + public void RemoveAll() + { + _caches.Clear(); + } + + /// + /// Clears a cache. + /// + public void ClearCache(TKey key) + { + if (_caches.TryGetValue(key, out var cache)) + cache.Clear(); + } + + /// + /// Clears all caches. + /// + public void ClearAllCaches() + { + foreach (var cache in _caches.Values) + cache.Clear(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Cache/CacheProviderExtensions.cs b/src/Umbraco.Core/Cache/CacheProviderExtensions.cs index e42cb4d9ad..0e41b981fb 100644 --- a/src/Umbraco.Core/Cache/CacheProviderExtensions.cs +++ b/src/Umbraco.Core/Cache/CacheProviderExtensions.cs @@ -10,7 +10,7 @@ namespace Umbraco.Core.Cache /// public static class CacheProviderExtensions { - public static T GetCacheItem(this IRuntimeCacheProvider provider, + public static T GetCacheItem(this IAppPolicedCache provider, string cacheKey, Func getCacheItem, TimeSpan? timeout, @@ -19,11 +19,11 @@ namespace Umbraco.Core.Cache CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) { - var result = provider.GetCacheItem(cacheKey, () => getCacheItem(), timeout, isSliding, priority, removedCallback, dependentFiles); + var result = provider.Get(cacheKey, () => getCacheItem(), timeout, isSliding, priority, removedCallback, dependentFiles); return result == null ? default(T) : result.TryConvertTo().Result; } - public static void InsertCacheItem(this IRuntimeCacheProvider provider, + public static void InsertCacheItem(this IAppPolicedCache provider, string cacheKey, Func getCacheItem, TimeSpan? timeout = null, @@ -32,24 +32,24 @@ namespace Umbraco.Core.Cache CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) { - provider.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, isSliding, priority, removedCallback, dependentFiles); + provider.Insert(cacheKey, () => getCacheItem(), timeout, isSliding, priority, removedCallback, dependentFiles); } - public static IEnumerable GetCacheItemsByKeySearch(this ICacheProvider provider, string keyStartsWith) + public static IEnumerable GetCacheItemsByKeySearch(this IAppCache provider, string keyStartsWith) { - var result = provider.GetCacheItemsByKeySearch(keyStartsWith); + var result = provider.SearchByKey(keyStartsWith); return result.Select(x => x.TryConvertTo().Result); } - public static IEnumerable GetCacheItemsByKeyExpression(this ICacheProvider provider, string regexString) + public static IEnumerable GetCacheItemsByKeyExpression(this IAppCache provider, string regexString) { - var result = provider.GetCacheItemsByKeyExpression(regexString); + var result = provider.SearchByRegex(regexString); return result.Select(x => x.TryConvertTo().Result); } - public static T GetCacheItem(this ICacheProvider provider, string cacheKey) + public static T GetCacheItem(this IAppCache provider, string cacheKey) { - var result = provider.GetCacheItem(cacheKey); + var result = provider.Get(cacheKey); if (result == null) { return default(T); @@ -57,9 +57,9 @@ namespace Umbraco.Core.Cache return result.TryConvertTo().Result; } - public static T GetCacheItem(this ICacheProvider provider, string cacheKey, Func getCacheItem) + public static T GetCacheItem(this IAppCache provider, string cacheKey, Func getCacheItem) { - var result = provider.GetCacheItem(cacheKey, () => getCacheItem()); + var result = provider.Get(cacheKey, () => getCacheItem()); if (result == null) { return default(T); diff --git a/src/Umbraco.Core/Cache/CacheRefresherBase.cs b/src/Umbraco.Core/Cache/CacheRefresherBase.cs index 5e6ec593af..bfa16ff3fa 100644 --- a/src/Umbraco.Core/Cache/CacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/CacheRefresherBase.cs @@ -102,7 +102,7 @@ namespace Umbraco.Core.Cache protected void ClearAllIsolatedCacheByEntityType() where TEntity : class, IEntity { - AppCaches.IsolatedRuntimeCache.ClearCache(); + AppCaches.IsolatedCaches.ClearCache(); } /// diff --git a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs new file mode 100644 index 0000000000..cdc66f1db7 --- /dev/null +++ b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Caching; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Entities; + +namespace Umbraco.Core.Cache +{ + /// + /// Implements by wrapping an inner other + /// instance, and ensuring that all inserts and returns are deep cloned copies of the cache item, + /// when the item is deep-cloneable. + /// + internal class DeepCloneAppCache : IAppPolicedCache + { + /// + /// Initializes a new instance of the class. + /// + public DeepCloneAppCache(IAppPolicedCache innerCache) + { + var type = typeof (DeepCloneAppCache); + + if (innerCache.GetType() == type) + throw new InvalidOperationException($"A {type} cannot wrap another instance of itself."); + + InnerCache = innerCache; + } + + /// + /// Gets the inner cache. + /// + public IAppPolicedCache InnerCache { get; } + + /// + public object Get(string key) + { + var item = InnerCache.Get(key); + return CheckCloneableAndTracksChanges(item); + } + + /// + public object Get(string key, Func factory) + { + var cached = InnerCache.Get(key, () => + { + var result = FastDictionaryAppCacheBase.GetSafeLazy(factory); + var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache + // do not store null values (backward compat), clone / reset to go into the cache + return value == null ? null : CheckCloneableAndTracksChanges(value); + }); + return CheckCloneableAndTracksChanges(cached); + } + + /// + public IEnumerable SearchByKey(string keyStartsWith) + { + return InnerCache.SearchByKey(keyStartsWith) + .Select(CheckCloneableAndTracksChanges); + } + + /// + public IEnumerable SearchByRegex(string regex) + { + return InnerCache.SearchByRegex(regex) + .Select(CheckCloneableAndTracksChanges); + } + + /// + public object Get(string key, Func factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + var cached = InnerCache.Get(key, () => + { + var result = FastDictionaryAppCacheBase.GetSafeLazy(factory); + var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache + // do not store null values (backward compat), clone / reset to go into the cache + return value == null ? null : CheckCloneableAndTracksChanges(value); + + // clone / reset to go into the cache + }, timeout, isSliding, priority, removedCallback, dependentFiles); + + // clone / reset to go into the cache + return CheckCloneableAndTracksChanges(cached); + } + + /// + public void Insert(string key, Func factory, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + InnerCache.Insert(key, () => + { + var result = FastDictionaryAppCacheBase.GetSafeLazy(factory); + var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache + // do not store null values (backward compat), clone / reset to go into the cache + return value == null ? null : CheckCloneableAndTracksChanges(value); + }, timeout, isSliding, priority, removedCallback, dependentFiles); + } + + /// + public void Clear() + { + InnerCache.Clear(); + } + + /// + public void Clear(string key) + { + InnerCache.Clear(key); + } + + /// + public void ClearOfType(string typeName) + { + InnerCache.ClearOfType(typeName); + } + + /// + public void ClearOfType() + { + InnerCache.ClearOfType(); + } + + /// + public void ClearOfType(Func predicate) + { + InnerCache.ClearOfType(predicate); + } + + /// + public void ClearByKey(string keyStartsWith) + { + InnerCache.ClearByKey(keyStartsWith); + } + + /// + public void ClearByRegex(string regex) + { + InnerCache.ClearByRegex(regex); + } + + private static object CheckCloneableAndTracksChanges(object input) + { + if (input is IDeepCloneable cloneable) + { + input = cloneable.DeepClone(); + } + + // reset dirty initial properties + if (input is IRememberBeingDirty tracksChanges) + { + tracksChanges.ResetDirtyProperties(false); + input = tracksChanges; + } + + return input; + } + } +} diff --git a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs deleted file mode 100644 index 255d7b526d..0000000000 --- a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web.Caching; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Entities; - -namespace Umbraco.Core.Cache -{ - /// - /// Interface describing this cache provider as a wrapper for another - /// - internal interface IRuntimeCacheProviderWrapper - { - IRuntimeCacheProvider InnerProvider { get; } - } - - /// - /// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns - /// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are - /// reset if the object is TracksChangesEntityBase - /// - internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper - { - public IRuntimeCacheProvider InnerProvider { get; } - - public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider) - { - var type = typeof (DeepCloneRuntimeCacheProvider); - - if (innerProvider.GetType() == type) - throw new InvalidOperationException($"A {type} cannot wrap another instance of {type}."); - - InnerProvider = innerProvider; - } - - #region Clear - doesn't require any changes - - public void ClearAllCache() - { - InnerProvider.ClearAllCache(); - } - - public void ClearCacheItem(string key) - { - InnerProvider.ClearCacheItem(key); - } - - public void ClearCacheObjectTypes(string typeName) - { - InnerProvider.ClearCacheObjectTypes(typeName); - } - - public void ClearCacheObjectTypes() - { - InnerProvider.ClearCacheObjectTypes(); - } - - public void ClearCacheObjectTypes(Func predicate) - { - InnerProvider.ClearCacheObjectTypes(predicate); - } - - public void ClearCacheByKeySearch(string keyStartsWith) - { - InnerProvider.ClearCacheByKeySearch(keyStartsWith); - } - - public void ClearCacheByKeyExpression(string regexString) - { - InnerProvider.ClearCacheByKeyExpression(regexString); - } - - #endregion - - public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) - { - return InnerProvider.GetCacheItemsByKeySearch(keyStartsWith) - .Select(CheckCloneableAndTracksChanges); - } - - public IEnumerable GetCacheItemsByKeyExpression(string regexString) - { - return InnerProvider.GetCacheItemsByKeyExpression(regexString) - .Select(CheckCloneableAndTracksChanges); - } - - public object GetCacheItem(string cacheKey) - { - var item = InnerProvider.GetCacheItem(cacheKey); - return CheckCloneableAndTracksChanges(item); - } - - public object GetCacheItem(string cacheKey, Func getCacheItem) - { - var cached = InnerProvider.GetCacheItem(cacheKey, () => - { - var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem); - var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache - if (value == null) return null; // do not store null values (backward compat) - - return CheckCloneableAndTracksChanges(value); - }); - return CheckCloneableAndTracksChanges(cached); - } - - public object GetCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - var cached = InnerProvider.GetCacheItem(cacheKey, () => - { - var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem); - var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache - if (value == null) return null; // do not store null values (backward compat) - - // clone / reset to go into the cache - return CheckCloneableAndTracksChanges(value); - }, timeout, isSliding, priority, removedCallback, dependentFiles); - - // clone / reset to go into the cache - return CheckCloneableAndTracksChanges(cached); - } - - public void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - InnerProvider.InsertCacheItem(cacheKey, () => - { - var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem); - var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache - if (value == null) return null; // do not store null values (backward compat) - - // clone / reset to go into the cache - return CheckCloneableAndTracksChanges(value); - }, timeout, isSliding, priority, removedCallback, dependentFiles); - } - - private static object CheckCloneableAndTracksChanges(object input) - { - var cloneable = input as IDeepCloneable; - if (cloneable != null) - { - input = cloneable.DeepClone(); - } - - // reset dirty initial properties (U4-1946) - var tracksChanges = input as IRememberBeingDirty; - if (tracksChanges != null) - { - tracksChanges.ResetDirtyProperties(false); - input = tracksChanges; - } - - return input; - } - } -} diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs index 8387f547d3..6f160cd552 100644 --- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Cache private static readonly TEntity[] EmptyEntities = new TEntity[0]; // const private readonly RepositoryCachePolicyOptions _options; - public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) + public DefaultRepositoryCachePolicy(IAppPolicedCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) : base(cache, scopeAccessor) { _options = options ?? throw new ArgumentNullException(nameof(options)); @@ -42,7 +42,7 @@ namespace Umbraco.Core.Cache protected virtual void InsertEntity(string cacheKey, TEntity entity) { - Cache.InsertCacheItem(cacheKey, () => entity, TimeSpan.FromMinutes(5), true); + Cache.Insert(cacheKey, () => entity, TimeSpan.FromMinutes(5), true); } protected virtual void InsertEntities(TId[] ids, TEntity[] entities) @@ -52,7 +52,7 @@ namespace Umbraco.Core.Cache // getting all of them, and finding nothing. // if we can cache a zero count, cache an empty array, // for as long as the cache is not cleared (no expiration) - Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => EmptyEntities); + Cache.Insert(GetEntityTypeCacheKey(), () => EmptyEntities); } else { @@ -60,7 +60,7 @@ namespace Umbraco.Core.Cache foreach (var entity in entities) { var capture = entity; - Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => capture, TimeSpan.FromMinutes(5), true); + Cache.Insert(GetEntityCacheKey(entity.Id), () => capture, TimeSpan.FromMinutes(5), true); } } } @@ -77,21 +77,21 @@ namespace Umbraco.Core.Cache // just to be safe, we cannot cache an item without an identity if (entity.HasIdentity) { - Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true); + Cache.Insert(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true); } // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared - Cache.ClearCacheItem(GetEntityTypeCacheKey()); + Cache.Clear(GetEntityTypeCacheKey()); } catch { // if an exception is thrown we need to remove the entry from cache, // this is ONLY a work around because of the way // that we cache entities: http://issues.umbraco.org/issue/U4-4259 - Cache.ClearCacheItem(GetEntityCacheKey(entity.Id)); + Cache.Clear(GetEntityCacheKey(entity.Id)); // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared - Cache.ClearCacheItem(GetEntityTypeCacheKey()); + Cache.Clear(GetEntityTypeCacheKey()); throw; } @@ -109,21 +109,21 @@ namespace Umbraco.Core.Cache // just to be safe, we cannot cache an item without an identity if (entity.HasIdentity) { - Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true); + Cache.Insert(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true); } // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared - Cache.ClearCacheItem(GetEntityTypeCacheKey()); + Cache.Clear(GetEntityTypeCacheKey()); } catch { // if an exception is thrown we need to remove the entry from cache, // this is ONLY a work around because of the way // that we cache entities: http://issues.umbraco.org/issue/U4-4259 - Cache.ClearCacheItem(GetEntityCacheKey(entity.Id)); + Cache.Clear(GetEntityCacheKey(entity.Id)); // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared - Cache.ClearCacheItem(GetEntityTypeCacheKey()); + Cache.Clear(GetEntityTypeCacheKey()); throw; } @@ -142,9 +142,9 @@ namespace Umbraco.Core.Cache { // whatever happens, clear the cache var cacheKey = GetEntityCacheKey(entity.Id); - Cache.ClearCacheItem(cacheKey); + Cache.Clear(cacheKey); // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared - Cache.ClearCacheItem(GetEntityTypeCacheKey()); + Cache.Clear(GetEntityTypeCacheKey()); } } @@ -238,7 +238,7 @@ namespace Umbraco.Core.Cache /// public override void ClearAll() { - Cache.ClearCacheByKeySearch(GetEntityTypeCacheKey()); + Cache.ClearByKey(GetEntityTypeCacheKey()); } } } diff --git a/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs b/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs index 98dceb80b0..2ff5f6ea83 100644 --- a/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs +++ b/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs @@ -1,147 +1,97 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Text.RegularExpressions; -using Umbraco.Core.Composing; namespace Umbraco.Core.Cache { - internal class DictionaryCacheProvider : ICacheProvider + /// + /// Implements on top of a concurrent dictionary. + /// + public class DictionaryCacheProvider : IAppCache { - private readonly ConcurrentDictionary> _items - = new ConcurrentDictionary>(); + /// + /// Gets the internal items dictionary, for tests only! + /// + internal readonly ConcurrentDictionary Items = new ConcurrentDictionary(); - // for tests - internal ConcurrentDictionary> Items => _items; - - public void ClearAllCache() + /// + public virtual object Get(string key) { - _items.Clear(); + // fixme throws if non-existing, shouldn't it return null? + return Items[key]; } - public void ClearCacheItem(string key) + /// + public virtual object Get(string key, Func factory) { - _items.TryRemove(key, out _); + return Items.GetOrAdd(key, _ => factory()); } - public void ClearCacheObjectTypes(string typeName) + /// + public virtual IEnumerable SearchByKey(string keyStartsWith) { - var type = TypeFinder.GetTypeByName(typeName); - if (type == null) return; - var isInterface = type.IsInterface; - - foreach (var kvp in _items - .Where(x => - { - // entry.Value is Lazy and not null, its value may be null - // remove null values as well, does not hurt - // get non-created as NonCreatedValue & exceptions as null - var value = DictionaryCacheProviderBase.GetSafeLazyValue(x.Value, true); - - // if T is an interface remove anything that implements that interface - // otherwise remove exact types (not inherited types) - return value == null || (isInterface ? (type.IsInstanceOfType(value)) : (value.GetType() == type)); - })) - _items.TryRemove(kvp.Key, out _); + var items = new List(); + foreach (var (key, value) in Items) + if (key.InvariantStartsWith(keyStartsWith)) + items.Add(value); + return items; } - public void ClearCacheObjectTypes() + /// + public IEnumerable SearchByRegex(string regex) + { + var compiled = new Regex(regex, RegexOptions.Compiled); + var items = new List(); + foreach (var (key, value) in Items) + if (compiled.IsMatch(key)) + items.Add(value); + return items; + } + + /// + public virtual void Clear() + { + Items.Clear(); + } + + /// + public virtual void Clear(string key) + { + Items.TryRemove(key, out _); + } + + /// + public virtual void ClearOfType(string typeName) + { + Items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType().ToString().InvariantEquals(typeName)); + } + + /// + public virtual void ClearOfType() { var typeOfT = typeof(T); - var isInterface = typeOfT.IsInterface; - - foreach (var kvp in _items - .Where(x => - { - // entry.Value is Lazy and not null, its value may be null - // remove null values as well, does not hurt - // compare on exact type, don't use "is" - // get non-created as NonCreatedValue & exceptions as null - var value = DictionaryCacheProviderBase.GetSafeLazyValue(x.Value, true); - - // if T is an interface remove anything that implements that interface - // otherwise remove exact types (not inherited types) - return value == null || (isInterface ? (value is T) : (value.GetType() == typeOfT)); - })) - _items.TryRemove(kvp.Key, out _); + Items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT); } - public void ClearCacheObjectTypes(Func predicate) + /// + public virtual void ClearOfType(Func predicate) { var typeOfT = typeof(T); - var isInterface = typeOfT.IsInterface; - - foreach (var kvp in _items - .Where(x => - { - // entry.Value is Lazy and not null, its value may be null - // remove null values as well, does not hurt - // compare on exact type, don't use "is" - // get non-created as NonCreatedValue & exceptions as null - var value = DictionaryCacheProviderBase.GetSafeLazyValue(x.Value, true); - if (value == null) return true; - - // if T is an interface remove anything that implements that interface - // otherwise remove exact types (not inherited types) - return (isInterface ? (value is T) : (value.GetType() == typeOfT)) - // run predicate on the 'public key' part only, ie without prefix - && predicate(x.Key, (T)value); - })) - _items.TryRemove(kvp.Key, out _); + Items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT && predicate(kvp.Key, (T)kvp.Value)); } - public void ClearCacheByKeySearch(string keyStartsWith) + /// + public virtual void ClearByKey(string keyStartsWith) { - foreach (var ikvp in _items - .Where(kvp => kvp.Key.InvariantStartsWith(keyStartsWith))) - _items.TryRemove(ikvp.Key, out _); + Items.RemoveAll(kvp => kvp.Key.InvariantStartsWith(keyStartsWith)); } - public void ClearCacheByKeyExpression(string regexString) + /// + public virtual void ClearByRegex(string regex) { - foreach (var ikvp in _items - .Where(kvp => Regex.IsMatch(kvp.Key, regexString))) - _items.TryRemove(ikvp.Key, out _); - } - - public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) - { - return _items - .Where(kvp => kvp.Key.InvariantStartsWith(keyStartsWith)) - .Select(kvp => DictionaryCacheProviderBase.GetSafeLazyValue(kvp.Value)) - .Where(x => x != null); - } - - public IEnumerable GetCacheItemsByKeyExpression(string regexString) - { - return _items - .Where(kvp => Regex.IsMatch(kvp.Key, regexString)) - .Select(kvp => DictionaryCacheProviderBase.GetSafeLazyValue(kvp.Value)) - .Where(x => x != null); - } - - public object GetCacheItem(string cacheKey) - { - _items.TryGetValue(cacheKey, out var result); // else null - return result == null ? null : DictionaryCacheProviderBase.GetSafeLazyValue(result); // return exceptions as null - } - - public object GetCacheItem(string cacheKey, Func getCacheItem) - { - var result = _items.GetOrAdd(cacheKey, k => DictionaryCacheProviderBase.GetSafeLazy(getCacheItem)); - - var value = result.Value; // will not throw (safe lazy) - if (!(value is DictionaryCacheProviderBase.ExceptionHolder eh)) - return value; - - // and... it's in the cache anyway - so contrary to other cache providers, - // which would trick with GetSafeLazyValue, we need to remove by ourselves, - // in order NOT to cache exceptions - - _items.TryRemove(cacheKey, out result); - eh.Exception.Throw(); // throw once! - return null; // never reached + var compiled = new Regex(regex, RegexOptions.Compiled); + Items.RemoveAll(kvp => compiled.IsMatch(kvp.Key)); } } } diff --git a/src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs similarity index 81% rename from src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs rename to src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs index f556d47a8e..371ab90a57 100644 --- a/src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs +++ b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs @@ -8,7 +8,10 @@ using Umbraco.Core.Composing; namespace Umbraco.Core.Cache { - internal abstract class DictionaryCacheProviderBase : ICacheProvider + /// + /// Provides a base class to fast, dictionary-based implementations. + /// + internal abstract class FastDictionaryAppCacheBase : IAppCache { // prefix cache keys so we know which one are ours protected const string CacheItemPrefix = "umbrtmche"; @@ -16,82 +19,75 @@ namespace Umbraco.Core.Cache // an object that represent a value that has not been created yet protected internal static readonly object ValueNotCreated = new object(); - // manupulate the underlying cache entries - // these *must* be called from within the appropriate locks - // and use the full prefixed cache keys - protected abstract IEnumerable GetDictionaryEntries(); - protected abstract void RemoveEntry(string key); - protected abstract object GetEntry(string key); + #region IAppCache - // read-write lock the underlying cache - //protected abstract IDisposable ReadLock { get; } - //protected abstract IDisposable WriteLock { get; } - - protected abstract void EnterReadLock(); - protected abstract void ExitReadLock(); - protected abstract void EnterWriteLock(); - protected abstract void ExitWriteLock(); - - protected string GetCacheKey(string key) + /// + public virtual object Get(string key) { - return string.Format("{0}-{1}", CacheItemPrefix, key); - } - - protected internal static Lazy GetSafeLazy(Func getCacheItem) - { - // try to generate the value and if it fails, - // wrap in an ExceptionHolder - would be much simpler - // to just use lazy.IsValueFaulted alas that field is - // internal - return new Lazy(() => - { - try - { - return getCacheItem(); - } - catch (Exception e) - { - return new ExceptionHolder(ExceptionDispatchInfo.Capture(e)); - } - }); - } - - protected internal static object GetSafeLazyValue(Lazy lazy, bool onlyIfValueIsCreated = false) - { - // if onlyIfValueIsCreated, do not trigger value creation - // must return something, though, to differenciate from null values - if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated; - - // if execution has thrown then lazy.IsValueCreated is false - // and lazy.IsValueFaulted is true (but internal) so we use our - // own exception holder (see Lazy source code) to return null - if (lazy.Value is ExceptionHolder) return null; - - // we have a value and execution has not thrown so returning - // here does not throw - unless we're re-entering, take care of it + key = GetCacheKey(key); + Lazy result; try { - return lazy.Value; + EnterReadLock(); + result = GetEntry(key) as Lazy; // null if key not found } - catch (InvalidOperationException e) + finally { - throw new InvalidOperationException("The method that computes a value for the cache has tried to read that value from the cache.", e); + ExitReadLock(); } + return result == null ? null : GetSafeLazyValue(result); // return exceptions as null } - internal class ExceptionHolder + /// + public abstract object Get(string key, Func factory); + + /// + public virtual IEnumerable SearchByKey(string keyStartsWith) { - public ExceptionHolder(ExceptionDispatchInfo e) + var plen = CacheItemPrefix.Length + 1; + IEnumerable entries; + try { - Exception = e; + EnterReadLock(); + entries = GetDictionaryEntries() + .Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith)) + .ToArray(); // evaluate while locked + } + finally + { + ExitReadLock(); } - public ExceptionDispatchInfo Exception { get; } + return entries + .Select(x => GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null + .Where(x => x != null); // backward compat, don't store null values in the cache } - #region Clear + /// + public virtual IEnumerable SearchByRegex(string regex) + { + const string prefix = CacheItemPrefix + "-"; + var compiled = new Regex(regex, RegexOptions.Compiled); + var plen = prefix.Length; + IEnumerable entries; + try + { + EnterReadLock(); + entries = GetDictionaryEntries() + .Where(x => compiled.IsMatch(((string)x.Key).Substring(plen))) + .ToArray(); // evaluate while locked + } + finally + { + ExitReadLock(); + } + return entries + .Select(x => GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null + .Where(x => x != null); // backward compat, don't store null values in the cache + } - public virtual void ClearAllCache() + /// + public virtual void Clear() { try { @@ -106,7 +102,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheItem(string key) + /// + public virtual void Clear(string key) { var cacheKey = GetCacheKey(key); try @@ -120,7 +117,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheObjectTypes(string typeName) + /// + public virtual void ClearOfType(string typeName) { var type = TypeFinder.GetTypeByName(typeName); if (type == null) return; @@ -149,7 +147,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheObjectTypes() + /// + public virtual void ClearOfType() { var typeOfT = typeof(T); var isInterface = typeOfT.IsInterface; @@ -178,7 +177,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheObjectTypes(Func predicate) + /// + public virtual void ClearOfType(Func predicate) { var typeOfT = typeof(T); var isInterface = typeOfT.IsInterface; @@ -210,7 +210,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheByKeySearch(string keyStartsWith) + /// + public virtual void ClearByKey(string keyStartsWith) { var plen = CacheItemPrefix.Length + 1; try @@ -227,14 +228,16 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheByKeyExpression(string regexString) + /// + public virtual void ClearByRegex(string regex) { + var compiled = new Regex(regex, RegexOptions.Compiled); var plen = CacheItemPrefix.Length + 1; try { EnterWriteLock(); foreach (var entry in GetDictionaryEntries() - .Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString)) + .Where(x => compiled.IsMatch(((string)x.Key).Substring(plen))) .ToArray()) RemoveEntry((string) entry.Key); } @@ -246,67 +249,80 @@ namespace Umbraco.Core.Cache #endregion - #region Get + #region Dictionary - public virtual IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) + // manipulate the underlying cache entries + // these *must* be called from within the appropriate locks + // and use the full prefixed cache keys + protected abstract IEnumerable GetDictionaryEntries(); + protected abstract void RemoveEntry(string key); + protected abstract object GetEntry(string key); + + // read-write lock the underlying cache + //protected abstract IDisposable ReadLock { get; } + //protected abstract IDisposable WriteLock { get; } + + protected abstract void EnterReadLock(); + protected abstract void ExitReadLock(); + protected abstract void EnterWriteLock(); + protected abstract void ExitWriteLock(); + + protected string GetCacheKey(string key) { - var plen = CacheItemPrefix.Length + 1; - IEnumerable entries; - try - { - EnterReadLock(); - entries = GetDictionaryEntries() - .Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith)) - .ToArray(); // evaluate while locked - } - finally - { - ExitReadLock(); - } - - return entries - .Select(x => GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null - .Where(x => x != null); // backward compat, don't store null values in the cache + return $"{CacheItemPrefix}-{key}"; } - public virtual IEnumerable GetCacheItemsByKeyExpression(string regexString) + protected internal static Lazy GetSafeLazy(Func getCacheItem) { - const string prefix = CacheItemPrefix + "-"; - var plen = prefix.Length; - IEnumerable entries; - try + // try to generate the value and if it fails, + // wrap in an ExceptionHolder - would be much simpler + // to just use lazy.IsValueFaulted alas that field is + // internal + return new Lazy(() => { - EnterReadLock(); - entries = GetDictionaryEntries() - .Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString)) - .ToArray(); // evaluate while locked - } - finally - { - ExitReadLock(); - } - return entries - .Select(x => GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null - .Where(x => x != null); // backward compat, don't store null values in the cache + try + { + return getCacheItem(); + } + catch (Exception e) + { + return new ExceptionHolder(ExceptionDispatchInfo.Capture(e)); + } + }); } - public virtual object GetCacheItem(string cacheKey) + protected internal static object GetSafeLazyValue(Lazy lazy, bool onlyIfValueIsCreated = false) { - cacheKey = GetCacheKey(cacheKey); - Lazy result; + // if onlyIfValueIsCreated, do not trigger value creation + // must return something, though, to differentiate from null values + if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated; + + // if execution has thrown then lazy.IsValueCreated is false + // and lazy.IsValueFaulted is true (but internal) so we use our + // own exception holder (see Lazy source code) to return null + if (lazy.Value is ExceptionHolder) return null; + + // we have a value and execution has not thrown so returning + // here does not throw - unless we're re-entering, take care of it try { - EnterReadLock(); - result = GetEntry(cacheKey) as Lazy; // null if key not found + return lazy.Value; } - finally + catch (InvalidOperationException e) { - ExitReadLock(); + throw new InvalidOperationException("The method that computes a value for the cache has tried to read that value from the cache.", e); } - return result == null ? null : GetSafeLazyValue(result); // return exceptions as null } - public abstract object GetCacheItem(string cacheKey, Func getCacheItem); + internal class ExceptionHolder + { + public ExceptionHolder(ExceptionDispatchInfo e) + { + Exception = e; + } + + public ExceptionDispatchInfo Exception { get; } + } #endregion } diff --git a/src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs b/src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs new file mode 100644 index 0000000000..a3863dac52 --- /dev/null +++ b/src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Umbraco.Core.Composing; + +namespace Umbraco.Core.Cache +{ + /// + /// Implements a fast on top of a concurrent dictionary. + /// + internal class FastDictionaryCacheProvider : IAppCache + { + /// + /// Gets the internal items dictionary, for tests only! + /// + internal readonly ConcurrentDictionary> Items = new ConcurrentDictionary>(); + + /// + public object Get(string cacheKey) + { + Items.TryGetValue(cacheKey, out var result); // else null + return result == null ? null : FastDictionaryAppCacheBase.GetSafeLazyValue(result); // return exceptions as null + } + + /// + public object Get(string cacheKey, Func getCacheItem) + { + var result = Items.GetOrAdd(cacheKey, k => FastDictionaryAppCacheBase.GetSafeLazy(getCacheItem)); + + var value = result.Value; // will not throw (safe lazy) + if (!(value is FastDictionaryAppCacheBase.ExceptionHolder eh)) + return value; + + // and... it's in the cache anyway - so contrary to other cache providers, + // which would trick with GetSafeLazyValue, we need to remove by ourselves, + // in order NOT to cache exceptions + + Items.TryRemove(cacheKey, out result); + eh.Exception.Throw(); // throw once! + return null; // never reached + } + + /// + public IEnumerable SearchByKey(string keyStartsWith) + { + return Items + .Where(kvp => kvp.Key.InvariantStartsWith(keyStartsWith)) + .Select(kvp => FastDictionaryAppCacheBase.GetSafeLazyValue(kvp.Value)) + .Where(x => x != null); + } + + /// + public IEnumerable SearchByRegex(string regex) + { + var compiled = new Regex(regex, RegexOptions.Compiled); + return Items + .Where(kvp => compiled.IsMatch(kvp.Key)) + .Select(kvp => FastDictionaryAppCacheBase.GetSafeLazyValue(kvp.Value)) + .Where(x => x != null); + } + + /// + public void Clear() + { + Items.Clear(); + } + + /// + public void Clear(string key) + { + Items.TryRemove(key, out _); + } + + /// + public void ClearOfType(string typeName) + { + var type = TypeFinder.GetTypeByName(typeName); + if (type == null) return; + var isInterface = type.IsInterface; + + foreach (var kvp in Items + .Where(x => + { + // entry.Value is Lazy and not null, its value may be null + // remove null values as well, does not hurt + // get non-created as NonCreatedValue & exceptions as null + var value = FastDictionaryAppCacheBase.GetSafeLazyValue(x.Value, true); + + // if T is an interface remove anything that implements that interface + // otherwise remove exact types (not inherited types) + return value == null || (isInterface ? (type.IsInstanceOfType(value)) : (value.GetType() == type)); + })) + Items.TryRemove(kvp.Key, out _); + } + + /// + public void ClearOfType() + { + var typeOfT = typeof(T); + var isInterface = typeOfT.IsInterface; + + foreach (var kvp in Items + .Where(x => + { + // entry.Value is Lazy and not null, its value may be null + // remove null values as well, does not hurt + // compare on exact type, don't use "is" + // get non-created as NonCreatedValue & exceptions as null + var value = FastDictionaryAppCacheBase.GetSafeLazyValue(x.Value, true); + + // if T is an interface remove anything that implements that interface + // otherwise remove exact types (not inherited types) + return value == null || (isInterface ? (value is T) : (value.GetType() == typeOfT)); + })) + Items.TryRemove(kvp.Key, out _); + } + + /// + public void ClearOfType(Func predicate) + { + var typeOfT = typeof(T); + var isInterface = typeOfT.IsInterface; + + foreach (var kvp in Items + .Where(x => + { + // entry.Value is Lazy and not null, its value may be null + // remove null values as well, does not hurt + // compare on exact type, don't use "is" + // get non-created as NonCreatedValue & exceptions as null + var value = FastDictionaryAppCacheBase.GetSafeLazyValue(x.Value, true); + if (value == null) return true; + + // if T is an interface remove anything that implements that interface + // otherwise remove exact types (not inherited types) + return (isInterface ? (value is T) : (value.GetType() == typeOfT)) + // run predicate on the 'public key' part only, ie without prefix + && predicate(x.Key, (T)value); + })) + Items.TryRemove(kvp.Key, out _); + } + + /// + public void ClearByKey(string keyStartsWith) + { + foreach (var ikvp in Items + .Where(kvp => kvp.Key.InvariantStartsWith(keyStartsWith))) + Items.TryRemove(ikvp.Key, out _); + } + + /// + public void ClearByRegex(string regex) + { + var compiled = new Regex(regex, RegexOptions.Compiled); + foreach (var ikvp in Items + .Where(kvp => compiled.IsMatch(kvp.Key))) + Items.TryRemove(ikvp.Key, out _); + } + } +} diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs index 319d84d41f..3bc4c9d059 100644 --- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core.Cache private readonly Func _entityGetId; private readonly bool _expires; - public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires) + public FullDataSetRepositoryCachePolicy(IAppPolicedCache cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires) : base(cache, scopeAccessor) { _entityGetId = entityGetId; @@ -55,11 +55,11 @@ namespace Umbraco.Core.Cache if (_expires) { - Cache.InsertCacheItem(key, () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true); + Cache.Insert(key, () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true); } else { - Cache.InsertCacheItem(key, () => new DeepCloneableList(entities)); + Cache.Insert(key, () => new DeepCloneableList(entities)); } } @@ -171,7 +171,7 @@ namespace Umbraco.Core.Cache /// public override void ClearAll() { - Cache.ClearCacheItem(GetEntityTypeCacheKey()); + Cache.Clear(GetEntityTypeCacheKey()); } } } diff --git a/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs similarity index 53% rename from src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs rename to src/Umbraco.Core/Cache/HttpRequestAppCache.cs index 52c230ff71..dcb2621d75 100644 --- a/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs +++ b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs @@ -7,54 +7,83 @@ using System.Web; namespace Umbraco.Core.Cache { /// - /// A cache provider that caches items in the HttpContext.Items + /// Implements a fast on top of HttpContext.Items. /// /// - /// If the Items collection is null, then this provider has no effect + /// If no current HttpContext items can be found (no current HttpContext, + /// or no Items...) then this cache acts as a pass-through and does not cache + /// anything. /// - internal class HttpRequestCacheProvider : DictionaryCacheProviderBase + internal class HttpRequestAppCache : FastDictionaryAppCacheBase { - // context provider - // the idea is that there is only one, application-wide HttpRequestCacheProvider instance, - // that is initialized with a method that returns the "current" context. - // NOTE - // but then it is initialized with () => new HttpContextWrapper(HttpContent.Current) - // which is higly inefficient because it creates a new wrapper each time we refer to _context() - // so replace it with _context1 and _context2 below + a way to get context.Items. - //private readonly Func _context; - - // NOTE - // and then in almost 100% cases _context2 will be () => HttpContext.Current - // so why not bring that logic in here and fallback on to HttpContext.Current when - // _context1 is null? - //private readonly HttpContextBase _context1; - //private readonly Func _context2; private readonly HttpContextBase _context; - private IDictionary ContextItems - { - //get { return _context1 != null ? _context1.Items : _context2().Items; } - get { return _context != null ? _context.Items : HttpContext.Current.Items; } - } - - private bool HasContextItems - { - get { return (_context != null && _context.Items != null) || HttpContext.Current != null; } - } - - // for unit tests - public HttpRequestCacheProvider(HttpContextBase context) + /// + /// Initializes a new instance of the class with a context, for unit tests! + /// + public HttpRequestAppCache(HttpContextBase context) { _context = context; } - // main constructor - // will use HttpContext.Current - public HttpRequestCacheProvider(/*Func context*/) + /// + /// Initializes a new instance of the class. + /// + /// + /// Will use HttpContext.Current. + /// fixme - should use IHttpContextAccessor + /// + public HttpRequestAppCache() + { } + + private IDictionary ContextItems => _context?.Items ?? HttpContext.Current?.Items; + + private bool HasContextItems => _context?.Items != null || HttpContext.Current != null; + + /// + public override object Get(string key, Func factory) { - //_context2 = context; + //no place to cache so just return the callback result + if (HasContextItems == false) return factory(); + + key = GetCacheKey(key); + + Lazy result; + + try + { + EnterWriteLock(); + result = ContextItems[key] as Lazy; // null if key not found + + // cannot create value within the lock, so if result.IsValueCreated is false, just + // do nothing here - means that if creation throws, a race condition could cause + // more than one thread to reach the return statement below and throw - accepted. + + if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null + { + result = GetSafeLazy(factory); + ContextItems[key] = result; + } + } + finally + { + ExitWriteLock(); + } + + // using GetSafeLazy and GetSafeLazyValue ensures that we don't cache + // exceptions (but try again and again) and silently eat them - however at + // some point we have to report them - so need to re-throw here + + // this does not throw anymore + //return result.Value; + + var value = result.Value; // will not throw (safe lazy) + if (value is ExceptionHolder eh) eh.Exception.Throw(); // throw once! + return value; } + #region Entries + protected override IEnumerable GetDictionaryEntries() { const string prefix = CacheItemPrefix + "-"; @@ -62,7 +91,7 @@ namespace Umbraco.Core.Cache if (HasContextItems == false) return Enumerable.Empty(); return ContextItems.Cast() - .Where(x => x.Key is string && ((string)x.Key).StartsWith(prefix)); + .Where(x => x.Key is string s && s.StartsWith(prefix)); } protected override void RemoveEntry(string key) @@ -77,6 +106,8 @@ namespace Umbraco.Core.Cache return HasContextItems ? ContextItems[key] : null; } + #endregion + #region Lock private bool _entered; @@ -103,59 +134,5 @@ namespace Umbraco.Core.Cache } #endregion - - #region Get - - public override object GetCacheItem(string cacheKey, Func getCacheItem) - { - //no place to cache so just return the callback result - if (HasContextItems == false) return getCacheItem(); - - cacheKey = GetCacheKey(cacheKey); - - Lazy result; - - try - { - EnterWriteLock(); - result = ContextItems[cacheKey] as Lazy; // null if key not found - - // cannot create value within the lock, so if result.IsValueCreated is false, just - // do nothing here - means that if creation throws, a race condition could cause - // more than one thread to reach the return statement below and throw - accepted. - - if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null - { - result = GetSafeLazy(getCacheItem); - ContextItems[cacheKey] = result; - } - } - finally - { - ExitWriteLock(); - } - - // using GetSafeLazy and GetSafeLazyValue ensures that we don't cache - // exceptions (but try again and again) and silently eat them - however at - // some point we have to report them - so need to re-throw here - - // this does not throw anymore - //return result.Value; - - var value = result.Value; // will not throw (safe lazy) - if (value is ExceptionHolder eh) eh.Exception.Throw(); // throw once! - return value; - } - - #endregion - - #region Insert - #endregion - - private class NoopLocker : DisposableObjectSlim - { - protected override void DisposeResources() - { } - } } } diff --git a/src/Umbraco.Core/Cache/IAppCache.cs b/src/Umbraco.Core/Cache/IAppCache.cs new file mode 100644 index 0000000000..674781f6d6 --- /dev/null +++ b/src/Umbraco.Core/Cache/IAppCache.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.Cache +{ + /// + /// Defines an application cache. + /// + public interface IAppCache + { + /// + /// Gets an item identified by its key. + /// + /// The key of the item. + /// The item, or null if the item was not found. + object Get(string key); + + /// + /// Gets or creates an item identified by its key. + /// + /// The key of the item. + /// A factory function that can create the item. + /// The item. + object Get(string key, Func factory); + + /// + /// Gets items with a key starting with the specified value. + /// + /// The StartsWith value to use in the search. + /// Items matching the search. + IEnumerable SearchByKey(string keyStartsWith); + + /// + /// Gets items with a key matching a regular expression. + /// + /// The regular expression. + /// Items matching the search. + IEnumerable SearchByRegex(string regex); + + /// + /// Removes all items from the cache. + /// + void Clear(); + + /// + /// Removes an item identified by its key from the cache. + /// + /// The key of the item. + void Clear(string key); + + /// + /// Removes items of a specified type from the cache. + /// + /// The name of the type to remove. + /// + /// If the type is an interface, then all items of a type implementing that interface are + /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from + /// the specified type are not removed). + /// Performs a case-sensitive search. + /// + void ClearOfType(string typeName); + + /// + /// Removes items of a specified type from the cache. + /// + /// The type of the items to remove. + /// If the type is an interface, then all items of a type implementing that interface are + /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from + /// the specified type are not removed). + void ClearOfType(); + + /// + /// Removes items of a specified type from the cache. + /// + /// The type of the items to remove. + /// The predicate to satisfy. + /// If the type is an interface, then all items of a type implementing that interface are + /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from + /// the specified type are not removed). + void ClearOfType(Func predicate); + + /// + /// Clears items with a key starting with the specified value. + /// + /// The StartsWith value to use in the search. + void ClearByKey(string keyStartsWith); + + /// + /// Clears items with a key matching a regular expression. + /// + /// The regular expression. + void ClearByRegex(string regex); + } +} diff --git a/src/Umbraco.Core/Cache/IAppPolicedCache.cs b/src/Umbraco.Core/Cache/IAppPolicedCache.cs new file mode 100644 index 0000000000..0aee7584df --- /dev/null +++ b/src/Umbraco.Core/Cache/IAppPolicedCache.cs @@ -0,0 +1,54 @@ +using System; +using System.Web.Caching; + +// fixme should this be/support non-web? + +namespace Umbraco.Core.Cache +{ + /// + /// Defines an application cache that support cache policies. + /// + /// A cache policy can be used to cache with timeouts, + /// or depending on files, and with a remove callback, etc. + public interface IAppPolicedCache : IAppCache + { + /// + /// Gets an item identified by its key. + /// + /// The key of the item. + /// A factory function that can create the item. + /// An optional cache timeout. + /// An optional value indicating whether the cache timeout is sliding (default is false). + /// An optional cache priority (default is Normal). + /// An optional callback to handle removals. + /// Files the cache entry depends on. + /// The item. + object Get( + string key, + Func factory, + TimeSpan? timeout, + bool isSliding = false, + CacheItemPriority priority = CacheItemPriority.Normal, + CacheItemRemovedCallback removedCallback = null, + string[] dependentFiles = null); + + /// + /// Inserts an item. + /// + /// The key of the item. + /// A factory function that can create the item. + /// An optional cache timeout. + /// An optional value indicating whether the cache timeout is sliding (default is false). + /// An optional cache priority (default is Normal). + /// An optional callback to handle removals. + /// Files the cache entry depends on. + void Insert( + string key, + Func factory, + TimeSpan? timeout = null, + bool isSliding = false, + CacheItemPriority priority = CacheItemPriority.Normal, + CacheItemRemovedCallback removedCallback = null, + string[] dependentFiles = null); + } +} diff --git a/src/Umbraco.Core/Cache/ICacheProvider.cs b/src/Umbraco.Core/Cache/ICacheProvider.cs deleted file mode 100644 index 177f7570c2..0000000000 --- a/src/Umbraco.Core/Cache/ICacheProvider.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Umbraco.Core.Cache -{ - /// - /// An interface for implementing a basic cache provider - /// - public interface ICacheProvider - { - /// - /// Removes all items from the cache. - /// - void ClearAllCache(); - - /// - /// Removes an item from the cache, identified by its key. - /// - /// The key of the item. - void ClearCacheItem(string key); - - /// - /// Removes items from the cache, of a specified type. - /// - /// The name of the type to remove. - /// - /// If the type is an interface, then all items of a type implementing that interface are - /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from - /// the specified type are not removed). - /// Performs a case-sensitive search. - /// - void ClearCacheObjectTypes(string typeName); - - /// - /// Removes items from the cache, of a specified type. - /// - /// The type of the items to remove. - /// If the type is an interface, then all items of a type implementing that interface are - /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from - /// the specified type are not removed). - void ClearCacheObjectTypes(); - - /// - /// Removes items from the cache, of a specified type, satisfying a predicate. - /// - /// The type of the items to remove. - /// The predicate to satisfy. - /// If the type is an interface, then all items of a type implementing that interface are - /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from - /// the specified type are not removed). - void ClearCacheObjectTypes(Func predicate); - - void ClearCacheByKeySearch(string keyStartsWith); - void ClearCacheByKeyExpression(string regexString); - - IEnumerable GetCacheItemsByKeySearch(string keyStartsWith); - IEnumerable GetCacheItemsByKeyExpression(string regexString); - - /// - /// Returns an item with a given key - /// - /// - /// - object GetCacheItem(string cacheKey); - - object GetCacheItem(string cacheKey, Func getCacheItem); - } -} diff --git a/src/Umbraco.Core/Cache/IRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/IRuntimeCacheProvider.cs deleted file mode 100644 index 9f3d687e1d..0000000000 --- a/src/Umbraco.Core/Cache/IRuntimeCacheProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Runtime.Caching; -using System.Text; -using System.Web.Caching; -using CacheItemPriority = System.Web.Caching.CacheItemPriority; - -namespace Umbraco.Core.Cache -{ - /// - /// An abstract class for implementing a runtime cache provider - /// - /// - /// - public interface IRuntimeCacheProvider : ICacheProvider - { - object GetCacheItem( - string cacheKey, - Func getCacheItem, - TimeSpan? timeout, - bool isSliding = false, - CacheItemPriority priority = CacheItemPriority.Normal, - CacheItemRemovedCallback removedCallback = null, - string[] dependentFiles = null); - - void InsertCacheItem( - string cacheKey, - Func getCacheItem, - TimeSpan? timeout = null, - bool isSliding = false, - CacheItemPriority priority = CacheItemPriority.Normal, - CacheItemRemovedCallback removedCallback = null, - string[] dependentFiles = null); - - } -} diff --git a/src/Umbraco.Core/Cache/IsolatedCaches.cs b/src/Umbraco.Core/Cache/IsolatedCaches.cs new file mode 100644 index 0000000000..bc624be20d --- /dev/null +++ b/src/Umbraco.Core/Cache/IsolatedCaches.cs @@ -0,0 +1,41 @@ +using System; + +namespace Umbraco.Core.Cache +{ + /// + /// Represents a dictionary of for types. + /// + /// + /// Isolated caches are used by e.g. repositories, to ensure that each cached entity + /// type has its own cache, so that lookups are fast and the repository does not need to + /// search through all keys on a global scale. + /// + public class IsolatedCaches : AppPolicedCacheDictionary + { + /// + /// Initializes a new instance of the class. + /// + /// + public IsolatedCaches(Func cacheFactory) + : base(cacheFactory) + { } + + /// + /// Gets a cache. + /// + public IAppPolicedCache GetOrCreate() + => GetOrCreate(typeof(T)); + + /// + /// Tries to get a cache. + /// + public Attempt Get() + => Get(typeof(T)); + + /// + /// Clears a cache. + /// + public void ClearCache() + => ClearCache(typeof(T)); + } +} diff --git a/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs b/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs deleted file mode 100644 index ee73a17532..0000000000 --- a/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Concurrent; - -namespace Umbraco.Core.Cache -{ - /// - /// Used to get/create/manipulate isolated runtime cache - /// - /// - /// This is useful for repository level caches to ensure that cache lookups by key are fast so - /// that the repository doesn't need to search through all keys on a global scale. - /// - public class IsolatedRuntimeCache - { - internal Func CacheFactory { get; set; } - - /// - /// Constructor that allows specifying a factory for the type of runtime isolated cache to create - /// - /// - public IsolatedRuntimeCache(Func cacheFactory) - { - CacheFactory = cacheFactory; - } - - private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); - - /// - /// Returns an isolated runtime cache for a given type - /// - /// - /// - public IRuntimeCacheProvider GetOrCreateCache() - { - return _isolatedCache.GetOrAdd(typeof(T), type => CacheFactory(type)); - } - - /// - /// Returns an isolated runtime cache for a given type - /// - /// - public IRuntimeCacheProvider GetOrCreateCache(Type type) - { - return _isolatedCache.GetOrAdd(type, t => CacheFactory(t)); - } - - /// - /// Tries to get a cache by the type specified - /// - /// - /// - public Attempt GetCache() - { - IRuntimeCacheProvider cache; - if (_isolatedCache.TryGetValue(typeof(T), out cache)) - { - return Attempt.Succeed(cache); - } - return Attempt.Fail(); - } - - /// - /// Clears all values inside this isolated runtime cache - /// - /// - /// - public void ClearCache() - { - IRuntimeCacheProvider cache; - if (_isolatedCache.TryGetValue(typeof(T), out cache)) - { - cache.ClearAllCache(); - } - } - - /// - /// Clears all of the isolated caches - /// - public void ClearAllCaches() - { - foreach (var key in _isolatedCache.Keys) - { - IRuntimeCacheProvider cache; - if (_isolatedCache.TryRemove(key, out cache)) - { - cache.ClearAllCache(); - } - } - } - } -} diff --git a/src/Umbraco.Core/Cache/NoAppCache.cs b/src/Umbraco.Core/Cache/NoAppCache.cs new file mode 100644 index 0000000000..8a7e15cb29 --- /dev/null +++ b/src/Umbraco.Core/Cache/NoAppCache.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Caching; + +namespace Umbraco.Core.Cache +{ + /// + /// Implements and do not cache. + /// + public class NoAppCache : IAppPolicedCache + { + private NoAppCache() { } + + /// + /// Gets the singleton instance. + /// + public static NoAppCache Instance { get; } = new NoAppCache(); + + /// + public virtual object Get(string cacheKey) + { + return null; + } + + /// + public virtual object Get(string cacheKey, Func factory) + { + return factory(); + } + + /// + public virtual IEnumerable SearchByKey(string keyStartsWith) + { + return Enumerable.Empty(); + } + + /// + public IEnumerable SearchByRegex(string regex) + { + return Enumerable.Empty(); + } + + /// + public object Get(string key, Func factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + return factory(); + } + + /// + public void Insert(string key, Func factory, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { } + + /// + public virtual void Clear() + { } + + /// + public virtual void Clear(string key) + { } + + /// + public virtual void ClearOfType(string typeName) + { } + + /// + public virtual void ClearOfType() + { } + + /// + public virtual void ClearOfType(Func predicate) + { } + + /// + public virtual void ClearByKey(string keyStartsWith) + { } + + /// + public virtual void ClearByRegex(string regex) + { } + } +} diff --git a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs index a3e7335d7f..acc67be679 100644 --- a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Cache public static NoCacheRepositoryCachePolicy Instance { get; } = new NoCacheRepositoryCachePolicy(); - public IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope) + public IRepositoryCachePolicy Scoped(IAppPolicedCache runtimeCache, IScope scope) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Core/Cache/NullCacheProvider.cs b/src/Umbraco.Core/Cache/NullCacheProvider.cs deleted file mode 100644 index 78286f75e2..0000000000 --- a/src/Umbraco.Core/Cache/NullCacheProvider.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web.Caching; - -namespace Umbraco.Core.Cache -{ - /// - /// Represents a cache provider that does not cache anything. - /// - public class NullCacheProvider : IRuntimeCacheProvider - { - private NullCacheProvider() { } - - public static NullCacheProvider Instance { get; } = new NullCacheProvider(); - - public virtual void ClearAllCache() - { } - - public virtual void ClearCacheItem(string key) - { } - - public virtual void ClearCacheObjectTypes(string typeName) - { } - - public virtual void ClearCacheObjectTypes() - { } - - public virtual void ClearCacheObjectTypes(Func predicate) - { } - - public virtual void ClearCacheByKeySearch(string keyStartsWith) - { } - - public virtual void ClearCacheByKeyExpression(string regexString) - { } - - public virtual IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) - { - return Enumerable.Empty(); - } - - public IEnumerable GetCacheItemsByKeyExpression(string regexString) - { - return Enumerable.Empty(); - } - - public virtual object GetCacheItem(string cacheKey) - { - return default(object); - } - - public virtual object GetCacheItem(string cacheKey, Func getCacheItem) - { - return getCacheItem(); - } - - public object GetCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - return getCacheItem(); - } - - public void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { } - } -} diff --git a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs similarity index 73% rename from src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs rename to src/Umbraco.Core/Cache/ObjectCacheAppCache.cs index 8a844bbc9b..9c5917a53c 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs @@ -11,31 +11,142 @@ using CacheItemPriority = System.Web.Caching.CacheItemPriority; namespace Umbraco.Core.Cache { /// - /// Represents a cache provider that caches item in a . - /// A cache provider that wraps the logic of a System.Runtime.Caching.ObjectCache + /// Implements on top of a . /// - /// The is created with name "in-memory". That name is - /// used to retrieve configuration options. It does not identify the memory cache, i.e. - /// each instance of this class has its own, independent, memory cache. - public class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider + public class ObjectCacheAppCache : IAppPolicedCache { private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - internal ObjectCache MemoryCache; /// - /// Used for debugging + /// Initializes a new instance of the . /// - internal Guid InstanceId { get; private set; } - - public ObjectCacheRuntimeCacheProvider() + public ObjectCacheAppCache() { + // the MemoryCache is created with name "in-memory". That name is + // used to retrieve configuration options. It does not identify the memory cache, i.e. + // each instance of this class has its own, independent, memory cache. MemoryCache = new MemoryCache("in-memory"); - InstanceId = Guid.NewGuid(); } - #region Clear + /// + /// Gets the internal memory cache, for tests only! + /// + internal readonly ObjectCache MemoryCache; - public virtual void ClearAllCache() + /// + public object Get(string key) + { + Lazy result; + try + { + _locker.EnterReadLock(); + result = MemoryCache.Get(key) as Lazy; // null if key not found + } + finally + { + if (_locker.IsReadLockHeld) + _locker.ExitReadLock(); + } + return result == null ? null : FastDictionaryAppCacheBase.GetSafeLazyValue(result); // return exceptions as null + } + + /// + public object Get(string key, Func factory) + { + return Get(key, factory, null); + } + + /// + public IEnumerable SearchByKey(string keyStartsWith) + { + KeyValuePair[] entries; + try + { + _locker.EnterReadLock(); + entries = MemoryCache + .Where(x => x.Key.InvariantStartsWith(keyStartsWith)) + .ToArray(); // evaluate while locked + } + finally + { + if (_locker.IsReadLockHeld) + _locker.ExitReadLock(); + } + return entries + .Select(x => FastDictionaryAppCacheBase.GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null + .Where(x => x != null) // backward compat, don't store null values in the cache + .ToList(); + } + + /// + public IEnumerable SearchByRegex(string regex) + { + var compiled = new Regex(regex, RegexOptions.Compiled); + + KeyValuePair[] entries; + try + { + _locker.EnterReadLock(); + entries = MemoryCache + .Where(x => compiled.IsMatch(x.Key)) + .ToArray(); // evaluate while locked + } + finally + { + if (_locker.IsReadLockHeld) + _locker.ExitReadLock(); + } + return entries + .Select(x => FastDictionaryAppCacheBase.GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null + .Where(x => x != null) // backward compat, don't store null values in the cache + .ToList(); + } + + /// + public object Get(string key, Func factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + // see notes in HttpRuntimeCacheProvider + + Lazy result; + + using (var lck = new UpgradeableReadLock(_locker)) + { + result = MemoryCache.Get(key) as Lazy; + if (result == null || FastDictionaryAppCacheBase.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null + { + result = FastDictionaryAppCacheBase.GetSafeLazy(factory); + var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles); + + lck.UpgradeToWriteLock(); + //NOTE: This does an add or update + MemoryCache.Set(key, result, policy); + } + } + + //return result.Value; + + var value = result.Value; // will not throw (safe lazy) + if (value is FastDictionaryAppCacheBase.ExceptionHolder eh) eh.Exception.Throw(); // throw once! + return value; + } + + /// + public void Insert(string key, Func factory, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + // NOTE - here also we must insert a Lazy but we can evaluate it right now + // and make sure we don't store a null value. + + var result = FastDictionaryAppCacheBase.GetSafeLazy(factory); + var value = result.Value; // force evaluation now + if (value == null) return; // do not store null values (backward compat) + + var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles); + //NOTE: This does an add or update + MemoryCache.Set(key, result, policy); + } + + /// + public virtual void Clear() { try { @@ -50,7 +161,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheItem(string key) + /// + public virtual void Clear(string key) { try { @@ -65,7 +177,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheObjectTypes(string typeName) + /// + public virtual void ClearOfType(string typeName) { var type = TypeFinder.GetTypeByName(typeName); if (type == null) return; @@ -79,7 +192,7 @@ namespace Umbraco.Core.Cache // x.Value is Lazy and not null, its value may be null // remove null values as well, does not hurt // get non-created as NonCreatedValue & exceptions as null - var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy)x.Value, true); + var value = FastDictionaryAppCacheBase.GetSafeLazyValue((Lazy)x.Value, true); // if T is an interface remove anything that implements that interface // otherwise remove exact types (not inherited types) @@ -96,12 +209,13 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheObjectTypes() + /// + public virtual void ClearOfType() { try { _locker.EnterWriteLock(); - var typeOfT = typeof (T); + var typeOfT = typeof(T); var isInterface = typeOfT.IsInterface; foreach (var key in MemoryCache .Where(x => @@ -109,7 +223,7 @@ namespace Umbraco.Core.Cache // x.Value is Lazy and not null, its value may be null // remove null values as well, does not hurt // get non-created as NonCreatedValue & exceptions as null - var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy)x.Value, true); + var value = FastDictionaryAppCacheBase.GetSafeLazyValue((Lazy)x.Value, true); // if T is an interface remove anything that implements that interface // otherwise remove exact types (not inherited types) @@ -127,7 +241,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheObjectTypes(Func predicate) + /// + public virtual void ClearOfType(Func predicate) { try { @@ -140,7 +255,7 @@ namespace Umbraco.Core.Cache // x.Value is Lazy and not null, its value may be null // remove null values as well, does not hurt // get non-created as NonCreatedValue & exceptions as null - var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy)x.Value, true); + var value = FastDictionaryAppCacheBase.GetSafeLazyValue((Lazy)x.Value, true); if (value == null) return true; // if T is an interface remove anything that implements that interface @@ -159,7 +274,8 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheByKeySearch(string keyStartsWith) + /// + public virtual void ClearByKey(string keyStartsWith) { try { @@ -177,13 +293,16 @@ namespace Umbraco.Core.Cache } } - public virtual void ClearCacheByKeyExpression(string regexString) + /// + public virtual void ClearByRegex(string regex) { + var compiled = new Regex(regex, RegexOptions.Compiled); + try { _locker.EnterWriteLock(); foreach (var key in MemoryCache - .Where(x => Regex.IsMatch(x.Key, regexString)) + .Where(x => compiled.IsMatch(x.Key)) .Select(x => x.Key) .ToArray()) // ToArray required to remove MemoryCache.Remove(key); @@ -195,120 +314,6 @@ namespace Umbraco.Core.Cache } } - #endregion - - #region Get - - public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) - { - KeyValuePair[] entries; - try - { - _locker.EnterReadLock(); - entries = MemoryCache - .Where(x => x.Key.InvariantStartsWith(keyStartsWith)) - .ToArray(); // evaluate while locked - } - finally - { - if (_locker.IsReadLockHeld) - _locker.ExitReadLock(); - } - return entries - .Select(x => DictionaryCacheProviderBase.GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null - .Where(x => x != null) // backward compat, don't store null values in the cache - .ToList(); - } - - public IEnumerable GetCacheItemsByKeyExpression(string regexString) - { - KeyValuePair[] entries; - try - { - _locker.EnterReadLock(); - entries = MemoryCache - .Where(x => Regex.IsMatch(x.Key, regexString)) - .ToArray(); // evaluate while locked - } - finally - { - if (_locker.IsReadLockHeld) - _locker.ExitReadLock(); - } - return entries - .Select(x => DictionaryCacheProviderBase.GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null - .Where(x => x != null) // backward compat, don't store null values in the cache - .ToList(); - } - - public object GetCacheItem(string cacheKey) - { - Lazy result; - try - { - _locker.EnterReadLock(); - result = MemoryCache.Get(cacheKey) as Lazy; // null if key not found - } - finally - { - if (_locker.IsReadLockHeld) - _locker.ExitReadLock(); - } - return result == null ? null : DictionaryCacheProviderBase.GetSafeLazyValue(result); // return exceptions as null - } - - public object GetCacheItem(string cacheKey, Func getCacheItem) - { - return GetCacheItem(cacheKey, getCacheItem, null); - } - - public object GetCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - // see notes in HttpRuntimeCacheProvider - - Lazy result; - - using (var lck = new UpgradeableReadLock(_locker)) - { - result = MemoryCache.Get(cacheKey) as Lazy; - if (result == null || DictionaryCacheProviderBase.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null - { - result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem); - var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles); - - lck.UpgradeToWriteLock(); - //NOTE: This does an add or update - MemoryCache.Set(cacheKey, result, policy); - } - } - - //return result.Value; - - var value = result.Value; // will not throw (safe lazy) - if (value is DictionaryCacheProviderBase.ExceptionHolder eh) eh.Exception.Throw(); // throw once! - return value; - } - - #endregion - - #region Insert - - public void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - // NOTE - here also we must insert a Lazy but we can evaluate it right now - // and make sure we don't store a null value. - - var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem); - var value = result.Value; // force evaluation now - if (value == null) return; // do not store null values (backward compat) - - var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles); - //NOTE: This does an add or update - MemoryCache.Set(cacheKey, result, policy); - } - - #endregion - private static CacheItemPolicy GetPolicy(TimeSpan? timeout = null, bool isSliding = false, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) { var absolute = isSliding ? ObjectCache.InfiniteAbsoluteExpiration : (timeout == null ? ObjectCache.InfiniteAbsoluteExpiration : DateTime.Now.Add(timeout.Value)); diff --git a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs index 2d21d410a7..f8bba4b033 100644 --- a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs +++ b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs @@ -13,16 +13,16 @@ namespace Umbraco.Core.Cache internal abstract class RepositoryCachePolicyBase : IRepositoryCachePolicy where TEntity : class, IEntity { - private readonly IRuntimeCacheProvider _globalCache; + private readonly IAppPolicedCache _globalCache; private readonly IScopeAccessor _scopeAccessor; - protected RepositoryCachePolicyBase(IRuntimeCacheProvider globalCache, IScopeAccessor scopeAccessor) + protected RepositoryCachePolicyBase(IAppPolicedCache globalCache, IScopeAccessor scopeAccessor) { _globalCache = globalCache ?? throw new ArgumentNullException(nameof(globalCache)); _scopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); } - protected IRuntimeCacheProvider Cache + protected IAppPolicedCache Cache { get { @@ -32,9 +32,9 @@ namespace Umbraco.Core.Cache case RepositoryCacheMode.Default: return _globalCache; case RepositoryCacheMode.Scoped: - return ambientScope.IsolatedRuntimeCache.GetOrCreateCache(); + return ambientScope.IsolatedCaches.GetOrCreate(); case RepositoryCacheMode.None: - return NullCacheProvider.Instance; + return NoAppCache.Instance; default: throw new NotSupportedException($"Repository cache mode {ambientScope.RepositoryCacheMode} is not supported."); } diff --git a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs index d89524d4f9..714798a47c 100644 --- a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Cache internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy where TEntity : class, IEntity { - public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) + public SingleItemsOnlyRepositoryCachePolicy(IAppPolicedCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) : base(cache, scopeAccessor, options) { } diff --git a/src/Umbraco.Core/Cache/StaticCacheProvider.cs b/src/Umbraco.Core/Cache/StaticCacheProvider.cs deleted file mode 100644 index 1604add4d7..0000000000 --- a/src/Umbraco.Core/Cache/StaticCacheProvider.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; - -namespace Umbraco.Core.Cache -{ - /// - /// Represents a cache provider that statically caches item in a concurrent dictionary. - /// - public class StaticCacheProvider : ICacheProvider - { - internal readonly ConcurrentDictionary StaticCache = new ConcurrentDictionary(); - - public virtual void ClearAllCache() - { - StaticCache.Clear(); - } - - public virtual void ClearCacheItem(string key) - { - object val; - StaticCache.TryRemove(key, out val); - } - - public virtual void ClearCacheObjectTypes(string typeName) - { - StaticCache.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType().ToString().InvariantEquals(typeName)); - } - - public virtual void ClearCacheObjectTypes() - { - var typeOfT = typeof(T); - StaticCache.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT); - } - - public virtual void ClearCacheObjectTypes(Func predicate) - { - var typeOfT = typeof(T); - StaticCache.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT && predicate(kvp.Key, (T)kvp.Value)); - } - - public virtual void ClearCacheByKeySearch(string keyStartsWith) - { - StaticCache.RemoveAll(kvp => kvp.Key.InvariantStartsWith(keyStartsWith)); - } - - public virtual void ClearCacheByKeyExpression(string regexString) - { - StaticCache.RemoveAll(kvp => Regex.IsMatch(kvp.Key, regexString)); - } - - public virtual IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) - { - return (from KeyValuePair c in StaticCache - where c.Key.InvariantStartsWith(keyStartsWith) - select c.Value).ToList(); - } - - public IEnumerable GetCacheItemsByKeyExpression(string regexString) - { - return (from KeyValuePair c in StaticCache - where Regex.IsMatch(c.Key, regexString) - select c.Value).ToList(); - } - - public virtual object GetCacheItem(string cacheKey) - { - var result = StaticCache[cacheKey]; - return result; - } - - public virtual object GetCacheItem(string cacheKey, Func getCacheItem) - { - return StaticCache.GetOrAdd(cacheKey, key => getCacheItem()); - } - } -} diff --git a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/WebCachingAppCache.cs similarity index 68% rename from src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs rename to src/Umbraco.Core/Cache/WebCachingAppCache.cs index 835c5d1ee6..b762fcda07 100644 --- a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/WebCachingAppCache.cs @@ -4,14 +4,15 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Web.Caching; -using CacheItemPriority = System.Web.Caching.CacheItemPriority; namespace Umbraco.Core.Cache { /// + /// Implements on top of a . /// A CacheProvider that wraps the logic of the HttpRuntime.Cache /// - internal class HttpRuntimeCacheProvider : DictionaryCacheProviderBase, IRuntimeCacheProvider + /// The underlying cache is expected to be HttpRuntime.Cache. + internal class WebCachingAppCache : FastDictionaryAppCacheBase, IAppPolicedCache { // locker object that supports upgradeable read locking // does not need to support recursion if we implement the cache correctly and ensure @@ -21,16 +22,43 @@ namespace Umbraco.Core.Cache private readonly System.Web.Caching.Cache _cache; /// - /// Used for debugging + /// Initializes a new instance of the class. /// - internal Guid InstanceId { get; private set; } - - public HttpRuntimeCacheProvider(System.Web.Caching.Cache cache) + public WebCachingAppCache(System.Web.Caching.Cache cache) { _cache = cache; - InstanceId = Guid.NewGuid(); } + /// + public override object Get(string key, Func factory) + { + return Get(key, factory, null, dependentFiles: null); + } + + /// + public object Get(string key, Func factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + CacheDependency dependency = null; + if (dependentFiles != null && dependentFiles.Any()) + { + dependency = new CacheDependency(dependentFiles); + } + return Get(key, factory, timeout, isSliding, priority, removedCallback, dependency); + } + + /// + public void Insert(string key, Func factory, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) + { + CacheDependency dependency = null; + if (dependentFiles != null && dependentFiles.Any()) + { + dependency = new CacheDependency(dependentFiles); + } + Insert(key, factory, timeout, isSliding, priority, removedCallback, dependency); + } + + #region Dictionary + protected override IEnumerable GetDictionaryEntries() { const string prefix = CacheItemPrefix + "-"; @@ -48,6 +76,8 @@ namespace Umbraco.Core.Cache return _cache.Get(key); } + #endregion + #region Lock protected override void EnterReadLock() @@ -74,33 +104,9 @@ namespace Umbraco.Core.Cache #endregion - #region Get - - /// - /// Gets (and adds if necessary) an item from the cache with all of the default parameters - /// - /// - /// - /// - public override object GetCacheItem(string cacheKey, Func getCacheItem) + private object Get(string key, Func factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null) { - return GetCacheItem(cacheKey, getCacheItem, null, dependentFiles: null); - } - - /// - /// This overload is here for legacy purposes - /// - /// - /// - /// - /// - /// - /// - /// - /// - internal object GetCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null) - { - cacheKey = GetCacheKey(cacheKey); + key = GetCacheKey(key); // NOTE - because we don't know what getCacheItem does, how long it will take and whether it will hang, // getCacheItem should run OUTSIDE of the global application lock else we run into lock contention and @@ -133,7 +139,7 @@ namespace Umbraco.Core.Cache try { _locker.EnterReadLock(); - result = _cache.Get(cacheKey) as Lazy; // null if key not found + result = _cache.Get(key) as Lazy; // null if key not found } finally { @@ -145,7 +151,7 @@ namespace Umbraco.Core.Cache using (var lck = new UpgradeableReadLock(_locker)) { - result = _cache.Get(cacheKey) as Lazy; // null if key not found + result = _cache.Get(key) as Lazy; // null if key not found // cannot create value within the lock, so if result.IsValueCreated is false, just // do nothing here - means that if creation throws, a race condition could cause @@ -153,13 +159,13 @@ namespace Umbraco.Core.Cache if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null { - result = GetSafeLazy(getCacheItem); + result = GetSafeLazy(factory); var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value)); var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration); lck.UpgradeToWriteLock(); //NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update! - _cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback); + _cache.Insert(key, result, dependency, absolute, sliding, priority, removedCallback); } } @@ -175,31 +181,7 @@ namespace Umbraco.Core.Cache return value; } - public object GetCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - CacheDependency dependency = null; - if (dependentFiles != null && dependentFiles.Any()) - { - dependency = new CacheDependency(dependentFiles); - } - return GetCacheItem(cacheKey, getCacheItem, timeout, isSliding, priority, removedCallback, dependency); - } - - #endregion - - #region Insert - - /// - /// This overload is here for legacy purposes - /// - /// - /// - /// - /// - /// - /// - /// - internal void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null) + private void Insert(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null) { // NOTE - here also we must insert a Lazy but we can evaluate it right now // and make sure we don't store a null value. @@ -225,17 +207,5 @@ namespace Umbraco.Core.Cache _locker.ExitWriteLock(); } } - - public void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - CacheDependency dependency = null; - if (dependentFiles != null && dependentFiles.Any()) - { - dependency = new CacheDependency(dependentFiles); - } - InsertCacheItem(cacheKey, getCacheItem, timeout, isSliding, priority, removedCallback, dependency); - } - - #endregion } } diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index acb12ab575..fe277676d7 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -29,7 +29,7 @@ namespace Umbraco.Core.Composing { private const string CacheKey = "umbraco-types.list"; - private readonly IRuntimeCacheProvider _runtimeCache; + private readonly IAppPolicedCache _runtimeCache; private readonly IProfilingLogger _logger; private readonly Dictionary _types = new Dictionary(); @@ -51,7 +51,7 @@ namespace Umbraco.Core.Composing /// The application runtime cache. /// Files storage mode. /// A profiling logger. - public TypeLoader(IRuntimeCacheProvider runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger) + public TypeLoader(IAppPolicedCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger) : this(runtimeCache, localTempStorage, logger, true) { } @@ -62,7 +62,7 @@ namespace Umbraco.Core.Composing /// Files storage mode. /// A profiling logger. /// Whether to detect changes using hashes. - internal TypeLoader(IRuntimeCacheProvider runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger, bool detectChanges) + internal TypeLoader(IAppPolicedCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger, bool detectChanges) { _runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); _localTempStorage = localTempStorage == LocalTempStorage.Unknown ? LocalTempStorage.Default : localTempStorage; @@ -478,7 +478,7 @@ namespace Umbraco.Core.Composing var typesHashFilePath = GetTypesHashFilePath(); DeleteFile(typesHashFilePath, FileDeleteTimeout); - _runtimeCache.ClearCacheItem(CacheKey); + _runtimeCache.Clear(CacheKey); } private Stream GetFileStream(string path, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, int timeoutMilliseconds) diff --git a/src/Umbraco.Core/ConfigsExtensions.cs b/src/Umbraco.Core/ConfigsExtensions.cs index 1414dbc852..9b2abda53c 100644 --- a/src/Umbraco.Core/ConfigsExtensions.cs +++ b/src/Umbraco.Core/ConfigsExtensions.cs @@ -46,7 +46,7 @@ namespace Umbraco.Core configs.Add(() => new CoreDebug()); // GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition - configs.Add(factory => new GridConfig(factory.GetInstance(), factory.GetInstance(), configDir, factory.GetInstance().Debug)); + configs.Add(factory => new GridConfig(factory.GetInstance(), factory.GetInstance(), configDir, factory.GetInstance().Debug)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs index 6c16a5e7ef..979eccb839 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration.Grid { class GridConfig : IGridConfig { - public GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo configFolder, bool isDebug) + public GridConfig(ILogger logger, IAppPolicedCache runtimeCache, DirectoryInfo configFolder, bool isDebug) { EditorsConfig = new GridEditorsConfig(logger, runtimeCache, configFolder, isDebug); } diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs index 94249aa135..121b74194c 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -13,11 +13,11 @@ namespace Umbraco.Core.Configuration.Grid internal class GridEditorsConfig : IGridEditorsConfig { private readonly ILogger _logger; - private readonly IRuntimeCacheProvider _runtimeCache; + private readonly IAppPolicedCache _runtimeCache; private readonly DirectoryInfo _configFolder; private readonly bool _isDebug; - public GridEditorsConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo configFolder, bool isDebug) + public GridEditorsConfig(ILogger logger, IAppPolicedCache runtimeCache, DirectoryInfo configFolder, bool isDebug) { _logger = logger; _runtimeCache = runtimeCache; diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index 59753df66a..fd344674af 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Manifest { private static readonly string Utf8Preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); - private readonly IRuntimeCacheProvider _cache; + private readonly IAppPolicedCache _cache; private readonly ILogger _logger; private readonly ManifestValueValidatorCollection _validators; @@ -29,14 +29,14 @@ namespace Umbraco.Core.Manifest /// /// Initializes a new instance of the class. /// - public ManifestParser(IRuntimeCacheProvider cache, ManifestValueValidatorCollection validators, ILogger logger) + public ManifestParser(IAppPolicedCache cache, ManifestValueValidatorCollection validators, ILogger logger) : this(cache, validators, "~/App_Plugins", logger) { } /// /// Initializes a new instance of the class. /// - private ManifestParser(IRuntimeCacheProvider cache, ManifestValueValidatorCollection validators, string path, ILogger logger) + private ManifestParser(IAppPolicedCache cache, ManifestValueValidatorCollection validators, string path, ILogger logger) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _validators = validators ?? throw new ArgumentNullException(nameof(validators)); diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index ba4d8cf590..7db3e3adbe 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -54,7 +54,7 @@ namespace Umbraco.Core.Models /// /// A list of 5 different sized avatar URLs /// - internal static string[] GetUserAvatarUrls(this IUser user, ICacheProvider staticCache) + internal static string[] GetUserAvatarUrls(this IUser user, IAppCache staticCache) { // If FIPS is required, never check the Gravatar service as it only supports MD5 hashing. // Unfortunately, if the FIPS setting is enabled on Windows, using MD5 will throw an exception diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs index bd55654809..8df9bf686d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs @@ -86,7 +86,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Database.Update(dto); entity.ResetDirtyProperties(); - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.Id)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Id)); } /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs index 3517fb3545..9b191d830c 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -174,8 +174,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.ResetDirtyProperties(); //Clear the cache entries that exist by uniqueid/item key - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.ItemKey)); - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.Key)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.ItemKey)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Key)); } protected override void PersistDeletedItem(IDictionaryItem entity) @@ -186,8 +186,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Database.Delete("WHERE id = @Id", new { Id = entity.Key }); //Clear the cache entries that exist by uniqueid/item key - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.ItemKey)); - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.Key)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.ItemKey)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Key)); entity.DeleteDate = DateTime.Now; } @@ -203,8 +203,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Database.Delete("WHERE id = @Id", new { Id = dto.UniqueId }); //Clear the cache entries that exist by uniqueid/item key - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(dto.Key)); - IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(dto.UniqueId)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(dto.Key)); + IsolatedCache.Clear(RepositoryCacheKeys.GetKey(dto.UniqueId)); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index 2626f60123..f106949c77 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected AppCaches GlobalCache { get; } - protected IRuntimeCacheProvider GlobalIsolatedCache => GlobalCache.IsolatedRuntimeCache.GetOrCreateCache(); + protected IAppPolicedCache GlobalIsolatedCache => GlobalCache.IsolatedCaches.GetOrCreate(); protected IScopeAccessor ScopeAccessor { get; } @@ -60,18 +60,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// Gets the isolated cache. /// /// Depends on the ambient scope cache mode. - protected IRuntimeCacheProvider IsolatedCache + protected IAppPolicedCache IsolatedCache { get { switch (AmbientScope.RepositoryCacheMode) { case RepositoryCacheMode.Default: - return GlobalCache.IsolatedRuntimeCache.GetOrCreateCache(); + return GlobalCache.IsolatedCaches.GetOrCreate(); case RepositoryCacheMode.Scoped: - return AmbientScope.IsolatedRuntimeCache.GetOrCreateCache(); + return AmbientScope.IsolatedCaches.GetOrCreate(); case RepositoryCacheMode.None: - return NullCacheProvider.Instance; + return NoAppCache.Instance; default: throw new Exception("oops: cache mode."); } @@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Adds or Updates an entity of type TEntity /// - /// This method is backed by an cache + /// This method is backed by an cache /// public void Save(TEntity entity) { diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index f29109b9d2..e37b5e254e 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -332,10 +332,10 @@ namespace Umbraco.Core.Runtime // is overriden by the web runtime return new AppCaches( - new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), - new StaticCacheProvider(), - NullCacheProvider.Instance, - new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))); + new DeepCloneAppCache(new ObjectCacheAppCache()), + new DictionaryCacheProvider(), + NoAppCache.Instance, + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } // by default, returns null, meaning that Umbraco should auto-detect the application root path. diff --git a/src/Umbraco.Core/Scoping/IScope.cs b/src/Umbraco.Core/Scoping/IScope.cs index eefc964965..de4eef0a08 100644 --- a/src/Umbraco.Core/Scoping/IScope.cs +++ b/src/Umbraco.Core/Scoping/IScope.cs @@ -38,7 +38,7 @@ namespace Umbraco.Core.Scoping /// /// Gets the scope isolated cache. /// - IsolatedRuntimeCache IsolatedRuntimeCache { get; } + IsolatedCaches IsolatedCaches { get; } /// /// Completes the scope. diff --git a/src/Umbraco.Core/Scoping/Scope.cs b/src/Umbraco.Core/Scoping/Scope.cs index b8d4d7b430..aa08016d3c 100644 --- a/src/Umbraco.Core/Scoping/Scope.cs +++ b/src/Umbraco.Core/Scoping/Scope.cs @@ -34,7 +34,7 @@ namespace Umbraco.Core.Scoping private bool _disposed; private bool? _completed; - private IsolatedRuntimeCache _isolatedRuntimeCache; + private IsolatedCaches _isolatedCaches; private IUmbracoDatabase _database; private EventMessages _messages; private ICompletable _fscope; @@ -177,14 +177,14 @@ namespace Umbraco.Core.Scoping } /// - public IsolatedRuntimeCache IsolatedRuntimeCache + public IsolatedCaches IsolatedCaches { get { - if (ParentScope != null) return ParentScope.IsolatedRuntimeCache; + if (ParentScope != null) return ParentScope.IsolatedCaches; - return _isolatedRuntimeCache ?? (_isolatedRuntimeCache - = new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))); + return _isolatedCaches ?? (_isolatedCaches + = new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } } diff --git a/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs b/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs index 3b3f90a412..5577508adb 100644 --- a/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs +++ b/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Services.Implement public class LocalizedTextServiceFileSources { private readonly ILogger _logger; - private readonly IRuntimeCacheProvider _cache; + private readonly IAppPolicedCache _cache; private readonly IEnumerable _supplementFileSources; private readonly DirectoryInfo _fileSourceFolder; @@ -37,7 +37,7 @@ namespace Umbraco.Core.Services.Implement /// public LocalizedTextServiceFileSources( ILogger logger, - IRuntimeCacheProvider cache, + IAppPolicedCache cache, DirectoryInfo fileSourceFolder, IEnumerable supplementFileSources) { @@ -140,7 +140,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - public LocalizedTextServiceFileSources(ILogger logger, IRuntimeCacheProvider cache, DirectoryInfo fileSourceFolder) + public LocalizedTextServiceFileSources(ILogger logger, IAppPolicedCache cache, DirectoryInfo fileSourceFolder) : this(logger, cache, fileSourceFolder, Enumerable.Empty()) { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 79162c06ad..41f2bc4951 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -109,6 +109,7 @@ + @@ -118,29 +119,29 @@ - + - - + + - - - + + + - - + + - - + + - + diff --git a/src/Umbraco.Tests/Cache/CacheProviderTests.cs b/src/Umbraco.Tests/Cache/CacheProviderTests.cs index d060df3c56..f2288cbaf2 100644 --- a/src/Umbraco.Tests/Cache/CacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/CacheProviderTests.cs @@ -9,7 +9,7 @@ namespace Umbraco.Tests.Cache { public abstract class CacheProviderTests { - internal abstract ICacheProvider Provider { get; } + internal abstract IAppCache Provider { get; } protected abstract int GetTotalItemCount { get; } [SetUp] @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Cache [TearDown] public virtual void TearDown() { - Provider.ClearAllCache(); + Provider.Clear(); } [Test] @@ -32,11 +32,11 @@ namespace Umbraco.Tests.Cache Assert.Ignore("Do not run for StaticCacheProvider."); Exception exception = null; - var result = Provider.GetCacheItem("blah", () => + var result = Provider.Get("blah", () => { try { - var result2 = Provider.GetCacheItem("blah"); + var result2 = Provider.Get("blah"); } catch (Exception e) { @@ -56,7 +56,7 @@ namespace Umbraco.Tests.Cache object result; try { - result = Provider.GetCacheItem("Blah", () => + result = Provider.Get("Blah", () => { counter++; throw new Exception("Do not cache this"); @@ -66,7 +66,7 @@ namespace Umbraco.Tests.Cache try { - result = Provider.GetCacheItem("Blah", () => + result = Provider.Get("Blah", () => { counter++; throw new Exception("Do not cache this"); @@ -85,13 +85,13 @@ namespace Umbraco.Tests.Cache object result; - result = Provider.GetCacheItem("Blah", () => + result = Provider.Get("Blah", () => { counter++; return ""; }); - result = Provider.GetCacheItem("Blah", () => + result = Provider.Get("Blah", () => { counter++; return ""; @@ -108,14 +108,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("Test1", () => cacheContent1); - Provider.GetCacheItem("Tester2", () => cacheContent2); - Provider.GetCacheItem("Tes3", () => cacheContent3); - Provider.GetCacheItem("different4", () => cacheContent4); + Provider.Get("Test1", () => cacheContent1); + Provider.Get("Tester2", () => cacheContent2); + Provider.Get("Tes3", () => cacheContent3); + Provider.Get("different4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - var result = Provider.GetCacheItemsByKeySearch("Tes"); + var result = Provider.SearchByKey("Tes"); Assert.AreEqual(3, result.Count()); } @@ -127,14 +127,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("TTes1t", () => cacheContent1); - Provider.GetCacheItem("Tester2", () => cacheContent2); - Provider.GetCacheItem("Tes3", () => cacheContent3); - Provider.GetCacheItem("different4", () => cacheContent4); + Provider.Get("TTes1t", () => cacheContent1); + Provider.Get("Tester2", () => cacheContent2); + Provider.Get("Tes3", () => cacheContent3); + Provider.Get("different4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearCacheByKeyExpression("^\\w+es\\d.*"); + Provider.ClearByRegex("^\\w+es\\d.*"); Assert.AreEqual(2, GetTotalItemCount); } @@ -146,14 +146,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("Test1", () => cacheContent1); - Provider.GetCacheItem("Tester2", () => cacheContent2); - Provider.GetCacheItem("Tes3", () => cacheContent3); - Provider.GetCacheItem("different4", () => cacheContent4); + Provider.Get("Test1", () => cacheContent1); + Provider.Get("Tester2", () => cacheContent2); + Provider.Get("Tes3", () => cacheContent3); + Provider.Get("different4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearCacheByKeySearch("Test"); + Provider.ClearByKey("Test"); Assert.AreEqual(2, GetTotalItemCount); } @@ -165,15 +165,15 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("Test1", () => cacheContent1); - Provider.GetCacheItem("Test2", () => cacheContent2); - Provider.GetCacheItem("Test3", () => cacheContent3); - Provider.GetCacheItem("Test4", () => cacheContent4); + Provider.Get("Test1", () => cacheContent1); + Provider.Get("Test2", () => cacheContent2); + Provider.Get("Test3", () => cacheContent3); + Provider.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearCacheItem("Test1"); - Provider.ClearCacheItem("Test2"); + Provider.Clear("Test1"); + Provider.Clear("Test2"); Assert.AreEqual(2, GetTotalItemCount); } @@ -185,14 +185,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("Test1", () => cacheContent1); - Provider.GetCacheItem("Test2", () => cacheContent2); - Provider.GetCacheItem("Test3", () => cacheContent3); - Provider.GetCacheItem("Test4", () => cacheContent4); + Provider.Get("Test1", () => cacheContent1); + Provider.Get("Test2", () => cacheContent2); + Provider.Get("Test3", () => cacheContent3); + Provider.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearAllCache(); + Provider.Clear(); Assert.AreEqual(0, GetTotalItemCount); } @@ -201,7 +201,7 @@ namespace Umbraco.Tests.Cache public void Can_Add_When_Not_Available() { var cacheContent1 = new MacroCacheContent(new LiteralControl(), "Test1"); - Provider.GetCacheItem("Test1", () => cacheContent1); + Provider.Get("Test1", () => cacheContent1); Assert.AreEqual(1, GetTotalItemCount); } @@ -209,8 +209,8 @@ namespace Umbraco.Tests.Cache public void Can_Get_When_Available() { var cacheContent1 = new MacroCacheContent(new LiteralControl(), "Test1"); - var result = Provider.GetCacheItem("Test1", () => cacheContent1); - var result2 = Provider.GetCacheItem("Test1", () => cacheContent1); + var result = Provider.Get("Test1", () => cacheContent1); + var result2 = Provider.Get("Test1", () => cacheContent1); Assert.AreEqual(1, GetTotalItemCount); Assert.AreEqual(result, result2); } @@ -222,15 +222,15 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("Test1", () => cacheContent1); - Provider.GetCacheItem("Test2", () => cacheContent2); - Provider.GetCacheItem("Test3", () => cacheContent3); - Provider.GetCacheItem("Test4", () => cacheContent4); + Provider.Get("Test1", () => cacheContent1); + Provider.Get("Test2", () => cacheContent2); + Provider.Get("Test3", () => cacheContent3); + Provider.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); //Provider.ClearCacheObjectTypes("umbraco.MacroCacheContent"); - Provider.ClearCacheObjectTypes(typeof(MacroCacheContent).ToString()); + Provider.ClearOfType(typeof(MacroCacheContent).ToString()); Assert.AreEqual(1, GetTotalItemCount); } @@ -242,14 +242,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.GetCacheItem("Test1", () => cacheContent1); - Provider.GetCacheItem("Test2", () => cacheContent2); - Provider.GetCacheItem("Test3", () => cacheContent3); - Provider.GetCacheItem("Test4", () => cacheContent4); + Provider.Get("Test1", () => cacheContent1); + Provider.Get("Test2", () => cacheContent2); + Provider.Get("Test3", () => cacheContent3); + Provider.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearCacheObjectTypes(); + Provider.ClearOfType(); Assert.AreEqual(1, GetTotalItemCount); } diff --git a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs index 169100153e..5158989a8b 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.Cache [TestFixture] public class DeepCloneRuntimeCacheProviderTests : RuntimeCacheProviderTests { - private DeepCloneRuntimeCacheProvider _provider; + private DeepCloneAppCache _provider; protected override int GetTotalItemCount { @@ -26,15 +26,15 @@ namespace Umbraco.Tests.Cache public override void Setup() { base.Setup(); - _provider = new DeepCloneRuntimeCacheProvider(new HttpRuntimeCacheProvider(HttpRuntime.Cache)); + _provider = new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache)); } - internal override ICacheProvider Provider + internal override IAppCache Provider { get { return _provider; } } - internal override IRuntimeCacheProvider RuntimeProvider + internal override IAppPolicedCache RuntimeProvider { get { return _provider; } } @@ -75,15 +75,15 @@ namespace Umbraco.Tests.Cache public void DoesNotCacheExceptions() { string value; - Assert.Throws(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(1)); }); - Assert.Throws(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(2)); }); + Assert.Throws(() => { value = (string)_provider.Get("key", () => GetValue(1)); }); + Assert.Throws(() => { value = (string)_provider.Get("key", () => GetValue(2)); }); // does not throw - value = (string)_provider.GetCacheItem("key", () => GetValue(3)); + value = (string)_provider.Get("key", () => GetValue(3)); Assert.AreEqual("succ3", value); // cache - value = (string)_provider.GetCacheItem("key", () => GetValue(4)); + value = (string)_provider.Get("key", () => GetValue(4)); Assert.AreEqual("succ3", value); } diff --git a/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs b/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs index 37488600c7..0f649328fe 100644 --- a/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs +++ b/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs @@ -28,8 +28,8 @@ namespace Umbraco.Tests.Cache public void Caches_Single() { var isCached = false; - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => { @@ -45,8 +45,8 @@ namespace Umbraco.Tests.Cache [Test] public void Get_Single_From_Cache() { - var cache = new Mock(); - cache.Setup(x => x.GetCacheItem(It.IsAny())).Returns(new AuditItem(1, AuditType.Copy, 123, "test", "blah")); + var cache = new Mock(); + cache.Setup(x => x.Get(It.IsAny())).Returns(new AuditItem(1, AuditType.Copy, 123, "test", "blah")); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); @@ -58,14 +58,14 @@ namespace Umbraco.Tests.Cache public void Caches_Per_Id_For_Get_All() { var cached = new List(); - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => { cached.Add(cacheKey); }); - cache.Setup(x => x.GetCacheItemsByKeySearch(It.IsAny())).Returns(new AuditItem[] {}); + cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new AuditItem[] {}); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); @@ -81,8 +81,8 @@ namespace Umbraco.Tests.Cache [Test] public void Get_All_Without_Ids_From_Cache() { - var cache = new Mock(); - cache.Setup(x => x.GetCacheItemsByKeySearch(It.IsAny())).Returns(new[] + var cache = new Mock(); + cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -98,8 +98,8 @@ namespace Umbraco.Tests.Cache public void If_CreateOrUpdate_Throws_Cache_Is_Removed() { var cacheCleared = false; - var cache = new Mock(); - cache.Setup(x => x.ClearCacheItem(It.IsAny())) + var cache = new Mock(); + cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { cacheCleared = true; @@ -124,8 +124,8 @@ namespace Umbraco.Tests.Cache public void If_Removes_Throws_Cache_Is_Removed() { var cacheCleared = false; - var cache = new Mock(); - cache.Setup(x => x.ClearCacheItem(It.IsAny())) + var cache = new Mock(); + cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { cacheCleared = true; diff --git a/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs b/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs index 404587bcfa..7c5a1524d2 100644 --- a/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs +++ b/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs @@ -37,8 +37,8 @@ namespace Umbraco.Tests.Cache }; var isCached = false; - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => { @@ -60,8 +60,8 @@ namespace Umbraco.Tests.Cache new AuditItem(2, AuditType.Copy, 123, "test", "blah2") }; - var cache = new Mock(); - cache.Setup(x => x.GetCacheItem(It.IsAny())).Returns(new AuditItem(1, AuditType.Copy, 123, "test", "blah")); + var cache = new Mock(); + cache.Setup(x => x.Get(It.IsAny())).Returns(new AuditItem(1, AuditType.Copy, 123, "test", "blah")); var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); @@ -78,8 +78,8 @@ namespace Umbraco.Tests.Cache IList list = null; - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => { @@ -87,7 +87,7 @@ namespace Umbraco.Tests.Cache list = o() as IList; }); - cache.Setup(x => x.GetCacheItem(It.IsAny())).Returns(() => + cache.Setup(x => x.Get(It.IsAny())).Returns(() => { //return null if this is the first pass return cached.Any() ? new DeepCloneableList(ListCloneBehavior.CloneOnce) : null; @@ -121,8 +121,8 @@ namespace Umbraco.Tests.Cache var cached = new List(); IList list = null; - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => { @@ -130,7 +130,7 @@ namespace Umbraco.Tests.Cache list = o() as IList; }); - cache.Setup(x => x.GetCacheItem(It.IsAny())).Returns(new AuditItem[] { }); + cache.Setup(x => x.Get(It.IsAny())).Returns(new AuditItem[] { }); var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); @@ -145,9 +145,9 @@ namespace Umbraco.Tests.Cache { var getAll = new[] { (AuditItem)null }; - var cache = new Mock(); + var cache = new Mock(); - cache.Setup(x => x.GetCacheItem(It.IsAny())).Returns(() => new DeepCloneableList(ListCloneBehavior.CloneOnce) + cache.Setup(x => x.Get(It.IsAny())).Returns(() => new DeepCloneableList(ListCloneBehavior.CloneOnce) { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -169,8 +169,8 @@ namespace Umbraco.Tests.Cache }; var cacheCleared = false; - var cache = new Mock(); - cache.Setup(x => x.ClearCacheItem(It.IsAny())) + var cache = new Mock(); + cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { cacheCleared = true; @@ -201,8 +201,8 @@ namespace Umbraco.Tests.Cache }; var cacheCleared = false; - var cache = new Mock(); - cache.Setup(x => x.ClearCacheItem(It.IsAny())) + var cache = new Mock(); + cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { cacheCleared = true; diff --git a/src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs b/src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs index cbb8d4e49d..f442319d7f 100644 --- a/src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs @@ -7,17 +7,17 @@ namespace Umbraco.Tests.Cache [TestFixture] public class HttpRequestCacheProviderTests : CacheProviderTests { - private HttpRequestCacheProvider _provider; + private HttpRequestAppCache _provider; private FakeHttpContextFactory _ctx; public override void Setup() { base.Setup(); _ctx = new FakeHttpContextFactory("http://localhost/test"); - _provider = new HttpRequestCacheProvider(_ctx.HttpContext); + _provider = new HttpRequestAppCache(_ctx.HttpContext); } - internal override ICacheProvider Provider + internal override IAppCache Provider { get { return _provider; } } @@ -31,22 +31,22 @@ namespace Umbraco.Tests.Cache [TestFixture] public class StaticCacheProviderTests : CacheProviderTests { - private StaticCacheProvider _provider; + private DictionaryCacheProvider _provider; public override void Setup() { base.Setup(); - _provider = new StaticCacheProvider(); + _provider = new DictionaryCacheProvider(); } - internal override ICacheProvider Provider + internal override IAppCache Provider { get { return _provider; } } protected override int GetTotalItemCount { - get { return _provider.StaticCache.Count; } + get { return _provider.Items.Count; } } } } diff --git a/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs index 679b8c5125..56f3303e9c 100644 --- a/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs @@ -9,7 +9,7 @@ namespace Umbraco.Tests.Cache [TestFixture] public class HttpRuntimeCacheProviderTests : RuntimeCacheProviderTests { - private HttpRuntimeCacheProvider _provider; + private WebCachingAppCache _provider; protected override int GetTotalItemCount { @@ -19,15 +19,15 @@ namespace Umbraco.Tests.Cache public override void Setup() { base.Setup(); - _provider = new HttpRuntimeCacheProvider(HttpRuntime.Cache); + _provider = new WebCachingAppCache(HttpRuntime.Cache); } - internal override ICacheProvider Provider + internal override IAppCache Provider { get { return _provider; } } - internal override IRuntimeCacheProvider RuntimeProvider + internal override IAppPolicedCache RuntimeProvider { get { return _provider; } } @@ -36,15 +36,15 @@ namespace Umbraco.Tests.Cache public void DoesNotCacheExceptions() { string value; - Assert.Throws(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(1)); }); - Assert.Throws(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(2)); }); + Assert.Throws(() => { value = (string)_provider.Get("key", () => GetValue(1)); }); + Assert.Throws(() => { value = (string)_provider.Get("key", () => GetValue(2)); }); // does not throw - value = (string)_provider.GetCacheItem("key", () => GetValue(3)); + value = (string)_provider.Get("key", () => GetValue(3)); Assert.AreEqual("succ3", value); // cache - value = (string)_provider.GetCacheItem("key", () => GetValue(4)); + value = (string)_provider.Get("key", () => GetValue(4)); Assert.AreEqual("succ3", value); } diff --git a/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs b/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs index e373fdda4d..6ed7f590e0 100644 --- a/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs @@ -10,7 +10,7 @@ namespace Umbraco.Tests.Cache [TestFixture] public class ObjectCacheProviderTests : RuntimeCacheProviderTests { - private ObjectCacheRuntimeCacheProvider _provider; + private ObjectCacheAppCache _provider; protected override int GetTotalItemCount { @@ -20,15 +20,15 @@ namespace Umbraco.Tests.Cache public override void Setup() { base.Setup(); - _provider = new ObjectCacheRuntimeCacheProvider(); + _provider = new ObjectCacheAppCache(); } - internal override ICacheProvider Provider + internal override IAppCache Provider { get { return _provider; } } - internal override IRuntimeCacheProvider RuntimeProvider + internal override IAppPolicedCache RuntimeProvider { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 12ea87087d..79d0dfb9da 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Cache.PublishedCache _xml = new XmlDocument(); _xml.LoadXml(GetXml()); var xmlStore = new XmlStore(() => _xml, null, null, null); - var cacheProvider = new StaticCacheProvider(); + var cacheProvider = new DictionaryCacheProvider(); var domainCache = new DomainCache(ServiceContext.DomainService, DefaultCultureAccessor); var publishedShapshot = new Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedSnapshot( new PublishedContentCache(xmlStore, domainCache, cacheProvider, globalSettings, new SiteDomainHelper(), ContentTypesCache, null, null), diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs index 6add88009d..ee16a1dede 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs @@ -75,7 +75,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var mChild2 = MakeNewMedia("Child2", mType, user, mRoot2.Id); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var roots = cache.GetAtRoot(); Assert.AreEqual(2, roots.Count()); Assert.IsTrue(roots.Select(x => x.Id).ContainsAll(new[] {mRoot1.Id, mRoot2.Id})); @@ -93,7 +93,7 @@ namespace Umbraco.Tests.Cache.PublishedCache //var publishedMedia = PublishedMediaTests.GetNode(mRoot.Id, GetUmbracoContext("/test", 1234)); var umbracoContext = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var publishedMedia = cache.GetById(mRoot.Id); Assert.IsNotNull(publishedMedia); @@ -204,7 +204,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var result = new SearchResult("1234", 1, () => fields.ToDictionary(x => x.Key, x => new List { x.Value })); - var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var doc = store.CreateFromCacheValues(store.ConvertFromSearchResult(result)); DoAssert(doc, 1234, key, templateIdVal: null, 0, "/media/test.jpg", "Image", 23, "Shannon", "Shannon", 0, 0, "-1,1234", DateTime.Parse("2012-07-17T10:34:09"), DateTime.Parse("2012-07-16T10:34:09"), 2); @@ -220,7 +220,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var xmlDoc = GetMediaXml(); ((XmlElement)xmlDoc.DocumentElement.FirstChild).SetAttribute("key", key.ToString()); var navigator = xmlDoc.SelectSingleNode("/root/Image").CreateNavigator(); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var doc = cache.CreateFromCacheValues(cache.ConvertFromXPathNavigator(navigator, true)); DoAssert(doc, 2000, key, templateIdVal: null, 2, "image1", "Image", 23, "Shannon", "Shannon", 33, 33, "-1,2000", DateTime.Parse("2012-06-12T14:13:17"), DateTime.Parse("2012-07-20T18:50:43"), 1); diff --git a/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs index e45dfd4250..08eb5e9a60 100644 --- a/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs @@ -8,7 +8,7 @@ namespace Umbraco.Tests.Cache public abstract class RuntimeCacheProviderTests : CacheProviderTests { - internal abstract IRuntimeCacheProvider RuntimeProvider { get; } + internal abstract IAppPolicedCache RuntimeProvider { get; } [Test] @@ -16,7 +16,7 @@ namespace Umbraco.Tests.Cache public void Can_Add_And_Expire_Struct_Strongly_Typed_With_Null() { var now = DateTime.Now; - RuntimeProvider.InsertCacheItem("DateTimeTest", () => now, new TimeSpan(0, 0, 0, 0, 200)); + RuntimeProvider.Insert("DateTimeTest", () => now, new TimeSpan(0, 0, 0, 0, 200)); Assert.AreEqual(now, Provider.GetCacheItem("DateTimeTest")); Assert.AreEqual(now, Provider.GetCacheItem("DateTimeTest")); diff --git a/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs b/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs index 1c2227f79b..2b37d85801 100644 --- a/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs +++ b/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs @@ -28,14 +28,14 @@ namespace Umbraco.Tests.Cache public void Get_All_Doesnt_Cache() { var cached = new List(); - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => { cached.Add(cacheKey); }); - cache.Setup(x => x.GetCacheItemsByKeySearch(It.IsAny())).Returns(new AuditItem[] { }); + cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new AuditItem[] { }); var defaultPolicy = new SingleItemsOnlyRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); @@ -52,8 +52,8 @@ namespace Umbraco.Tests.Cache public void Caches_Single() { var isCached = false; - var cache = new Mock(); - cache.Setup(x => x.InsertCacheItem(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), + var cache = new Mock(); + cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => { diff --git a/src/Umbraco.Tests/Composing/ComposingTestBase.cs b/src/Umbraco.Tests/Composing/ComposingTestBase.cs index 48850afd97..407d953509 100644 --- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests/Composing/ComposingTestBase.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Composing { ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of()); - TypeLoader = new TypeLoader(NullCacheProvider.Instance, LocalTempStorage.Default, ProfilingLogger, detectChanges: false) + TypeLoader = new TypeLoader(NoAppCache.Instance, LocalTempStorage.Default, ProfilingLogger, detectChanges: false) { AssembliesToScan = AssembliesToScan }; diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 1649f3675d..add3424599 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Composing public void Initialize() { // this ensures it's reset - _typeLoader = new TypeLoader(NullCacheProvider.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of())); + _typeLoader = new TypeLoader(NoAppCache.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of())); foreach (var file in Directory.GetFiles(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache"))) File.Delete(file); diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests/CoreThings/UdiTests.cs index 2b4ace8810..35080e8c24 100644 --- a/src/Umbraco.Tests/CoreThings/UdiTests.cs +++ b/src/Umbraco.Tests/CoreThings/UdiTests.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests.CoreThings var container = new Mock(); var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); container.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns( - new TypeLoader(NullCacheProvider.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of()))); + new TypeLoader(NoAppCache.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of()))); Current.Factory = container.Object; Udi.ResetUdiTypes(); diff --git a/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs b/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs index 7508395c64..088ef6b54b 100644 --- a/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs +++ b/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs @@ -413,7 +413,7 @@ namespace Umbraco.Tests.FrontEnd container .Setup(x => x.GetInstance(typeof(TypeLoader))) .Returns(new TypeLoader( - NullCacheProvider.Instance, + NoAppCache.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of()) ) diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 23e198b778..225bd17618 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -22,10 +22,10 @@ namespace Umbraco.Tests.Macros { //we DO want cache enabled for these tests var cacheHelper = new AppCaches( - new ObjectCacheRuntimeCacheProvider(), - new StaticCacheProvider(), - NullCacheProvider.Instance, - new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); + new ObjectCacheAppCache(), + new DictionaryCacheProvider(), + NoAppCache.Instance, + new IsolatedCaches(type => new ObjectCacheAppCache())); //Current.ApplicationContext = new ApplicationContext(cacheHelper, new ProfilingLogger(Mock.Of(), Mock.Of())); Current.Reset(); diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs index ce3d1d705c..74f9fd7157 100644 --- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs @@ -44,7 +44,7 @@ namespace Umbraco.Tests.Manifest new RequiredValidator(Mock.Of()), new RegexValidator(Mock.Of(), null) }; - _parser = new ManifestParser(NullCacheProvider.Instance, new ManifestValueValidatorCollection(validators), Mock.Of()); + _parser = new ManifestParser(NoAppCache.Instance, new ManifestValueValidatorCollection(validators), Mock.Of()); } [Test] diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index ea5614fb85..14f766fba1 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -232,8 +232,8 @@ namespace Umbraco.Tests.Models content.UpdateDate = DateTime.Now; content.WriterId = 23; - var runtimeCache = new ObjectCacheRuntimeCacheProvider(); - runtimeCache.InsertCacheItem(content.Id.ToString(CultureInfo.InvariantCulture), () => content); + var runtimeCache = new ObjectCacheAppCache(); + runtimeCache.Insert(content.Id.ToString(CultureInfo.InvariantCulture), () => content); var proflog = GetTestProfilingLogger(); @@ -241,7 +241,7 @@ namespace Umbraco.Tests.Models { for (int j = 0; j < 1000; j++) { - var clone = runtimeCache.GetCacheItem(content.Id.ToString(CultureInfo.InvariantCulture)); + var clone = runtimeCache.Get(content.Id.ToString(CultureInfo.InvariantCulture)); } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index 772147f5ad..1641631f43 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -76,10 +76,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void CacheActiveForIntsAndGuids() { var realCache = new AppCaches( - new ObjectCacheRuntimeCacheProvider(), - new StaticCacheProvider(), - new StaticCacheProvider(), - new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())); + new ObjectCacheAppCache(), + new DictionaryCacheProvider(), + new DictionaryCacheProvider(), + new IsolatedCaches(t => new ObjectCacheAppCache())); var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index 5e1900b29e..33c8524bb4 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -47,10 +47,10 @@ namespace Umbraco.Tests.Persistence.Repositories MediaTypeRepository mediaTypeRepository; var realCache = new AppCaches( - new ObjectCacheRuntimeCacheProvider(), - new StaticCacheProvider(), - new StaticCacheProvider(), - new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())); + new ObjectCacheAppCache(), + new DictionaryCacheProvider(), + new DictionaryCacheProvider(), + new IsolatedCaches(t => new ObjectCacheAppCache())); var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs index 33a595626e..04444855fb 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs @@ -118,8 +118,8 @@ namespace Umbraco.Tests.Published publishedContentTypeFactory.CreatePropertyType("prop1", 1), }); - var elementsCache = new DictionaryCacheProvider(); - var snapshotCache = new DictionaryCacheProvider(); + var elementsCache = new FastDictionaryCacheProvider(); + var snapshotCache = new FastDictionaryCacheProvider(); var publishedSnapshot = new Mock(); publishedSnapshot.Setup(x => x.SnapshotCache).Returns(snapshotCache); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 6b280832da..5b1dcde728 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -40,7 +40,7 @@ namespace Umbraco.Tests.PublishedContent Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes())); } - protected override TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + protected override TypeLoader CreateTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 603464e18b..e798be82c4 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -74,7 +74,7 @@ namespace Umbraco.Tests.PublishedContent ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType; } - protected override TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + protected override TypeLoader CreateTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 4f55b4fd71..4257e3dabb 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -68,7 +68,7 @@ namespace Umbraco.Tests.PublishedContent internal IPublishedContent GetNode(int id, UmbracoContext umbracoContext) { var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), - ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, + ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var doc = cache.GetById(id); Assert.IsNotNull(doc); @@ -126,7 +126,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -156,7 +156,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //ensure it is found var publishedMedia = cache.GetById(3113); @@ -203,7 +203,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -231,7 +231,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -259,7 +259,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -288,7 +288,7 @@ namespace Umbraco.Tests.PublishedContent var ctx = GetUmbracoContext("/test"); var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(3113); @@ -314,7 +314,7 @@ namespace Umbraco.Tests.PublishedContent var ctx = GetUmbracoContext("/test"); var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(3113); @@ -482,7 +482,7 @@ namespace Umbraco.Tests.PublishedContent "); var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var nav = node.CreateNavigator(); @@ -502,7 +502,7 @@ namespace Umbraco.Tests.PublishedContent var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); var nav = errorXml.CreateNavigator(); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); Assert.IsNull(converted); diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index deaecf821e..f7077ecb3a 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -36,9 +36,9 @@ namespace Umbraco.Tests.PublishedContent public void Resync() { } - public ICacheProvider SnapshotCache => null; + public IAppCache SnapshotCache => null; - public ICacheProvider ElementsCache => null; + public IAppCache ElementsCache => null; } class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index 5d4fa4f182..6e01de1670 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -41,10 +41,10 @@ namespace Umbraco.Tests.Scoping { // this is what's created core web runtime return new AppCaches( - new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), - new StaticCacheProvider(), - NullCacheProvider.Instance, - new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))); + new DeepCloneAppCache(new ObjectCacheAppCache()), + new DictionaryCacheProvider(), + NoAppCache.Instance, + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } [TearDown] @@ -60,13 +60,13 @@ namespace Umbraco.Tests.Scoping { var scopeProvider = ScopeProvider; var service = Current.Services.UserService; - var globalCache = Current.ApplicationCache.IsolatedRuntimeCache.GetOrCreateCache(typeof(IUser)); + var globalCache = Current.ApplicationCache.IsolatedCaches.GetOrCreate(typeof(IUser)); var user = (IUser)new User("name", "email", "username", "rawPassword"); service.Save(user); // global cache contains the entity - var globalCached = (IUser) globalCache.GetCacheItem(GetCacheIdKey(user.Id), () => null); + var globalCached = (IUser) globalCache.Get(GetCacheIdKey(user.Id), () => null); Assert.IsNotNull(globalCached); Assert.AreEqual(user.Id, globalCached.Id); Assert.AreEqual("name", globalCached.Name); @@ -85,20 +85,20 @@ namespace Umbraco.Tests.Scoping Assert.AreSame(scope, scopeProvider.AmbientScope); // scope has its own isolated cache - var scopedCache = scope.IsolatedRuntimeCache.GetOrCreateCache(typeof (IUser)); + var scopedCache = scope.IsolatedCaches.GetOrCreate(typeof (IUser)); Assert.AreNotSame(globalCache, scopedCache); user.Name = "changed"; service.Save(user); // scoped cache contains the "new" entity - var scopeCached = (IUser) scopedCache.GetCacheItem(GetCacheIdKey(user.Id), () => null); + var scopeCached = (IUser) scopedCache.Get(GetCacheIdKey(user.Id), () => null); Assert.IsNotNull(scopeCached); Assert.AreEqual(user.Id, scopeCached.Id); Assert.AreEqual("changed", scopeCached.Name); // global cache is unchanged - globalCached = (IUser) globalCache.GetCacheItem(GetCacheIdKey(user.Id), () => null); + globalCached = (IUser) globalCache.Get(GetCacheIdKey(user.Id), () => null); Assert.IsNotNull(globalCached); Assert.AreEqual(user.Id, globalCached.Id); Assert.AreEqual("name", globalCached.Name); @@ -108,7 +108,7 @@ namespace Umbraco.Tests.Scoping } Assert.IsNull(scopeProvider.AmbientScope); - globalCached = (IUser) globalCache.GetCacheItem(GetCacheIdKey(user.Id), () => null); + globalCached = (IUser) globalCache.Get(GetCacheIdKey(user.Id), () => null); if (complete) { // global cache has been cleared @@ -125,7 +125,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual(complete ? "changed" : "name", user.Name); // global cache contains the entity again - globalCached = (IUser) globalCache.GetCacheItem(GetCacheIdKey(user.Id), () => null); + globalCached = (IUser) globalCache.Get(GetCacheIdKey(user.Id), () => null); Assert.IsNotNull(globalCached); Assert.AreEqual(user.Id, globalCached.Id); Assert.AreEqual(complete ? "changed" : "name", globalCached.Name); @@ -137,18 +137,18 @@ namespace Umbraco.Tests.Scoping { var scopeProvider = ScopeProvider; var service = Current.Services.LocalizationService; - var globalCache = Current.ApplicationCache.IsolatedRuntimeCache.GetOrCreateCache(typeof (ILanguage)); + var globalCache = Current.ApplicationCache.IsolatedCaches.GetOrCreate(typeof (ILanguage)); var lang = (ILanguage) new Language("fr-FR"); service.Save(lang); // global cache has been flushed, reload - var globalFullCached = (IEnumerable) globalCache.GetCacheItem(GetCacheTypeKey(), () => null); + var globalFullCached = (IEnumerable) globalCache.Get(GetCacheTypeKey(), () => null); Assert.IsNull(globalFullCached); var reload = service.GetLanguageById(lang.Id); // global cache contains the entity - globalFullCached = (IEnumerable) globalCache.GetCacheItem(GetCacheTypeKey(), () => null); + globalFullCached = (IEnumerable) globalCache.Get(GetCacheTypeKey(), () => null); Assert.IsNotNull(globalFullCached); var globalCached = globalFullCached.First(x => x.Id == lang.Id); Assert.IsNotNull(globalCached); @@ -166,19 +166,19 @@ namespace Umbraco.Tests.Scoping Assert.AreSame(scope, scopeProvider.AmbientScope); // scope has its own isolated cache - var scopedCache = scope.IsolatedRuntimeCache.GetOrCreateCache(typeof (ILanguage)); + var scopedCache = scope.IsolatedCaches.GetOrCreate(typeof (ILanguage)); Assert.AreNotSame(globalCache, scopedCache); lang.IsoCode = "de-DE"; service.Save(lang); // scoped cache has been flushed, reload - var scopeFullCached = (IEnumerable) scopedCache.GetCacheItem(GetCacheTypeKey(), () => null); + var scopeFullCached = (IEnumerable) scopedCache.Get(GetCacheTypeKey(), () => null); Assert.IsNull(scopeFullCached); reload = service.GetLanguageById(lang.Id); // scoped cache contains the "new" entity - scopeFullCached = (IEnumerable) scopedCache.GetCacheItem(GetCacheTypeKey(), () => null); + scopeFullCached = (IEnumerable) scopedCache.Get(GetCacheTypeKey(), () => null); Assert.IsNotNull(scopeFullCached); var scopeCached = scopeFullCached.First(x => x.Id == lang.Id); Assert.IsNotNull(scopeCached); @@ -186,7 +186,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual("de-DE", scopeCached.IsoCode); // global cache is unchanged - globalFullCached = (IEnumerable) globalCache.GetCacheItem(GetCacheTypeKey(), () => null); + globalFullCached = (IEnumerable) globalCache.Get(GetCacheTypeKey(), () => null); Assert.IsNotNull(globalFullCached); globalCached = globalFullCached.First(x => x.Id == lang.Id); Assert.IsNotNull(globalCached); @@ -198,7 +198,7 @@ namespace Umbraco.Tests.Scoping } Assert.IsNull(scopeProvider.AmbientScope); - globalFullCached = (IEnumerable) globalCache.GetCacheItem(GetCacheTypeKey(), () => null); + globalFullCached = (IEnumerable) globalCache.Get(GetCacheTypeKey(), () => null); if (complete) { // global cache has been cleared @@ -215,7 +215,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual(complete ? "de-DE" : "fr-FR", lang.IsoCode); // global cache contains the entity again - globalFullCached = (IEnumerable) globalCache.GetCacheItem(GetCacheTypeKey(), () => null); + globalFullCached = (IEnumerable) globalCache.Get(GetCacheTypeKey(), () => null); Assert.IsNotNull(globalFullCached); globalCached = globalFullCached.First(x => x.Id == lang.Id); Assert.IsNotNull(globalCached); @@ -229,7 +229,7 @@ namespace Umbraco.Tests.Scoping { var scopeProvider = ScopeProvider; var service = Current.Services.LocalizationService; - var globalCache = Current.ApplicationCache.IsolatedRuntimeCache.GetOrCreateCache(typeof (IDictionaryItem)); + var globalCache = Current.ApplicationCache.IsolatedCaches.GetOrCreate(typeof (IDictionaryItem)); var lang = (ILanguage)new Language("fr-FR"); service.Save(lang); @@ -242,7 +242,7 @@ namespace Umbraco.Tests.Scoping service.Save(item); // global cache contains the entity - var globalCached = (IDictionaryItem) globalCache.GetCacheItem(GetCacheIdKey(item.Id), () => null); + var globalCached = (IDictionaryItem) globalCache.Get(GetCacheIdKey(item.Id), () => null); Assert.IsNotNull(globalCached); Assert.AreEqual(item.Id, globalCached.Id); Assert.AreEqual("item-key", globalCached.ItemKey); @@ -258,20 +258,20 @@ namespace Umbraco.Tests.Scoping Assert.AreSame(scope, scopeProvider.AmbientScope); // scope has its own isolated cache - var scopedCache = scope.IsolatedRuntimeCache.GetOrCreateCache(typeof (IDictionaryItem)); + var scopedCache = scope.IsolatedCaches.GetOrCreate(typeof (IDictionaryItem)); Assert.AreNotSame(globalCache, scopedCache); item.ItemKey = "item-changed"; service.Save(item); // scoped cache contains the "new" entity - var scopeCached = (IDictionaryItem) scopedCache.GetCacheItem(GetCacheIdKey(item.Id), () => null); + var scopeCached = (IDictionaryItem) scopedCache.Get(GetCacheIdKey(item.Id), () => null); Assert.IsNotNull(scopeCached); Assert.AreEqual(item.Id, scopeCached.Id); Assert.AreEqual("item-changed", scopeCached.ItemKey); // global cache is unchanged - globalCached = (IDictionaryItem) globalCache.GetCacheItem(GetCacheIdKey(item.Id), () => null); + globalCached = (IDictionaryItem) globalCache.Get(GetCacheIdKey(item.Id), () => null); Assert.IsNotNull(globalCached); Assert.AreEqual(item.Id, globalCached.Id); Assert.AreEqual("item-key", globalCached.ItemKey); @@ -281,7 +281,7 @@ namespace Umbraco.Tests.Scoping } Assert.IsNull(scopeProvider.AmbientScope); - globalCached = (IDictionaryItem) globalCache.GetCacheItem(GetCacheIdKey(item.Id), () => null); + globalCached = (IDictionaryItem) globalCache.Get(GetCacheIdKey(item.Id), () => null); if (complete) { // global cache has been cleared @@ -298,7 +298,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual(complete ? "item-changed" : "item-key", item.ItemKey); // global cache contains the entity again - globalCached = (IDictionaryItem) globalCache.GetCacheItem(GetCacheIdKey(item.Id), () => null); + globalCached = (IDictionaryItem) globalCache.Get(GetCacheIdKey(item.Id), () => null); Assert.IsNotNull(globalCached); Assert.AreEqual(item.Id, globalCached.Id); Assert.AreEqual(complete ? "item-changed" : "item-key", globalCached.ItemKey); diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index 7fd2f0f18b..35fcc853d4 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -38,7 +38,7 @@ namespace Umbraco.Tests.TestHelpers var container = RegisterFactory.Create(); var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); - var typeLoader = new TypeLoader(NullCacheProvider.Instance, + var typeLoader = new TypeLoader(NoAppCache.Instance, LocalTempStorage.Default, logger, false); diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 0729aa0b6e..2deb30bbdd 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -246,7 +246,7 @@ namespace Umbraco.Tests.TestHelpers protected virtual IPublishedSnapshotService CreatePublishedSnapshotService() { - var cache = NullCacheProvider.Instance; + var cache = NoAppCache.Instance; ContentTypesCache = new PublishedContentTypeCache( Factory.GetInstance(), diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index c980f9c1ee..2d6e01b6bb 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -245,7 +245,7 @@ namespace Umbraco.Tests.Testing .ComposeWebMappingProfiles(); } - protected virtual TypeLoader GetTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option) + protected virtual TypeLoader GetTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option) { switch (option) { @@ -260,13 +260,13 @@ namespace Umbraco.Tests.Testing } } - protected virtual TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + protected virtual TypeLoader CreateTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { return CreateCommonTypeLoader(runtimeCache, globalSettings, logger); } // common to all tests = cannot be overriden - private static TypeLoader CreateCommonTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + private static TypeLoader CreateCommonTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { return new TypeLoader(runtimeCache, globalSettings.LocalTempStorageLocation, logger, false) { diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index 192b0975d1..133cbb2ee7 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -415,7 +415,7 @@ namespace Umbraco.Tests.Web.Mvc // CacheHelper.CreateDisabledCacheHelper(), // new ProfilingLogger(logger, Mock.Of())) { /*IsReady = true*/ }; - var cache = NullCacheProvider.Instance; + var cache = NoAppCache.Instance; //var provider = new ScopeUnitOfWorkProvider(databaseFactory, new RepositoryFactory(Mock.Of())); var scopeProvider = TestObjects.GetScopeProvider(Mock.Of()); var factory = Mock.Of(); diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs index 047d0b0b8f..e95ae7b785 100644 --- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs +++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs @@ -39,7 +39,7 @@ namespace Umbraco.Tests.Web // fixme - bad in a unit test - but Udi has a static ctor that wants it?! var factory = new Mock(); factory.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns( - new TypeLoader(NullCacheProvider.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of()))); + new TypeLoader(NoAppCache.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of()))); factory.Setup(x => x.GetInstance(typeof (ServiceContext))).Returns(serviceContext); var settings = SettingsForTests.GetDefaultUmbracoSettings(); diff --git a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs index cf93b44215..751b2194b7 100644 --- a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + AppCaches.RuntimeCache.Clear(CacheKeys.ApplicationsCacheKey); base.RefreshAll(); } @@ -37,7 +37,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + AppCaches.RuntimeCache.Clear(CacheKeys.ApplicationsCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs index 72fceec631..4d2dcd8efb 100644 --- a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + AppCaches.RuntimeCache.Clear(CacheKeys.ApplicationTreeCacheKey); base.RefreshAll(); } @@ -37,7 +37,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - AppCaches.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + AppCaches.RuntimeCache.Clear(CacheKeys.ApplicationTreeCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs index 3ae2f8e3dd..36397540b6 100644 --- a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs @@ -44,14 +44,14 @@ namespace Umbraco.Web.Cache public override void Refresh(JsonPayload[] payloads) { - AppCaches.RuntimeCache.ClearCacheObjectTypes(); + AppCaches.RuntimeCache.ClearOfType(); var idsRemoved = new HashSet(); - var isolatedCache = AppCaches.IsolatedRuntimeCache.GetOrCreateCache(); + var isolatedCache = AppCaches.IsolatedCaches.GetOrCreate(); foreach (var payload in payloads) { - isolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(payload.Id)); + isolatedCache.Clear(RepositoryCacheKeys.GetKey(payload.Id)); _idkMap.ClearCache(payload.Id); @@ -59,7 +59,7 @@ namespace Umbraco.Web.Cache if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.RefreshBranch | TreeChangeTypes.Remove)) { var pathid = "," + payload.Id + ","; - isolatedCache.ClearCacheObjectTypes((k, v) => v.Path.Contains(pathid)); + isolatedCache.ClearOfType((k, v) => v.Path.Contains(pathid)); } //if the item is being completely removed, we need to refresh the domains cache if any domain was assigned to the content @@ -162,8 +162,8 @@ namespace Umbraco.Web.Cache appCaches.ClearPartialViewCache(); MacroCacheRefresher.ClearMacroContentCache(appCaches); // just the content - appCaches.IsolatedRuntimeCache.ClearCache(); - appCaches.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedCaches.ClearCache(); + appCaches.IsolatedCaches.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index e1a8f05e39..f3d1337403 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache ClearAllIsolatedCacheByEntityType(); ClearAllIsolatedCacheByEntityType(); - var dataTypeCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var dataTypeCache = AppCaches.IsolatedCaches.Get(); foreach (var payload in payloads) { diff --git a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs index cdeb2ffdd0..6b739b4f49 100644 --- a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs @@ -33,11 +33,11 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { foreach (var prefix in GetAllMacroCacheKeys()) - AppCaches.RuntimeCache.ClearCacheByKeySearch(prefix); + AppCaches.RuntimeCache.ClearByKey(prefix); ClearAllIsolatedCacheByEntityType(); - AppCaches.RuntimeCache.ClearCacheObjectTypes(); + AppCaches.RuntimeCache.ClearOfType(); base.RefreshAll(); } @@ -49,12 +49,12 @@ namespace Umbraco.Web.Cache foreach (var payload in payloads) { foreach (var alias in GetCacheKeysForAlias(payload.Alias)) - AppCaches.RuntimeCache.ClearCacheByKeySearch(alias); + AppCaches.RuntimeCache.ClearByKey(alias); - var macroRepoCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var macroRepoCache = AppCaches.IsolatedCaches.Get(); if (macroRepoCache) { - macroRepoCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(payload.Id)); + macroRepoCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id)); } }; @@ -112,7 +112,7 @@ namespace Umbraco.Web.Cache public static void ClearMacroContentCache(AppCaches appCaches) { - appCaches.RuntimeCache.ClearCacheObjectTypes(); + appCaches.RuntimeCache.ClearOfType(); } #endregion diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index a6ccd7e005..cdaf43dac3 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache { Current.ApplicationCache.ClearPartialViewCache(); - var mediaCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var mediaCache = AppCaches.IsolatedCaches.Get(); foreach (var payload in payloads) { @@ -61,13 +61,13 @@ namespace Umbraco.Web.Cache // repository cache // it *was* done for each pathId but really that does not make sense // only need to do it for the current media - mediaCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(payload.Id)); + mediaCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id)); // remove those that are in the branch if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.RefreshBranch | TreeChangeTypes.Remove)) { var pathid = "," + payload.Id + ","; - mediaCache.Result.ClearCacheObjectTypes((_, v) => v.Path.Contains(pathid)); + mediaCache.Result.ClearOfType((_, v) => v.Path.Contains(pathid)); } } } @@ -121,7 +121,7 @@ namespace Umbraco.Web.Cache public static void RefreshMediaTypes(AppCaches appCaches) { - appCaches.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedCaches.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs index 29c102e7a2..1565b1c849 100644 --- a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs @@ -60,9 +60,9 @@ namespace Umbraco.Web.Cache _idkMap.ClearCache(id); AppCaches.ClearPartialViewCache(); - var memberCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var memberCache = AppCaches.IsolatedCaches.Get(); if (memberCache) - memberCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); + memberCache.Result.Clear(RepositoryCacheKeys.GetKey(id)); } #endregion @@ -71,7 +71,7 @@ namespace Umbraco.Web.Cache public static void RefreshMemberTypes(AppCaches appCaches) { - appCaches.IsolatedRuntimeCache.ClearCache(); + appCaches.IsolatedCaches.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs index 9368b0f9f4..3e195cec5e 100644 --- a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache // Since we cache by group name, it could be problematic when renaming to // previously existing names - see http://issues.umbraco.org/issue/U4-10846. // To work around this, just clear all the cache items - AppCaches.IsolatedRuntimeCache.ClearCache(); + AppCaches.IsolatedCaches.ClearCache(); } #endregion diff --git a/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs index 8b1c8581cd..c9c8b47bbf 100644 --- a/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs @@ -34,8 +34,8 @@ namespace Umbraco.Web.Cache public override void Refresh(int id) { - var cache = AppCaches.IsolatedRuntimeCache.GetCache(); - if (cache) cache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); + var cache = AppCaches.IsolatedCaches.Get(); + if (cache) cache.Result.Clear(RepositoryCacheKeys.GetKey(id)); base.Refresh(id); } @@ -47,8 +47,8 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - var cache = AppCaches.IsolatedRuntimeCache.GetCache(); - if (cache) cache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); + var cache = AppCaches.IsolatedCaches.Get(); + if (cache) cache.Result.Clear(RepositoryCacheKeys.GetKey(id)); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs index 7ff7c6fdb6..eda3b6eef4 100644 --- a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.Cache private void RemoveFromCache(int id) { _idkMap.ClearCache(id); - AppCaches.RuntimeCache.ClearCacheItem($"{CacheKeys.TemplateFrontEndCacheKey}{id}"); + AppCaches.RuntimeCache.Clear($"{CacheKeys.TemplateFrontEndCacheKey}{id}"); //need to clear the runtime cache for templates ClearAllIsolatedCacheByEntityType(); diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index a502a7554f..922a9df385 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -40,9 +40,9 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - var userCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var userCache = AppCaches.IsolatedCaches.Get(); if (userCache) - userCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); + userCache.Result.Clear(RepositoryCacheKeys.GetKey(id)); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs index 4dea595c85..cfdf8f3669 100644 --- a/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserGroupCacheRefresher.cs @@ -35,10 +35,10 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { ClearAllIsolatedCacheByEntityType(); - var userGroupCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var userGroupCache = AppCaches.IsolatedCaches.Get(); if (userGroupCache) { - userGroupCache.Result.ClearCacheByKeySearch(UserGroupRepository.GetByAliasCacheKeyPrefix); + userGroupCache.Result.ClearByKey(UserGroupRepository.GetByAliasCacheKeyPrefix); } //We'll need to clear all user cache too @@ -55,11 +55,11 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - var userGroupCache = AppCaches.IsolatedRuntimeCache.GetCache(); + var userGroupCache = AppCaches.IsolatedCaches.Get(); if (userGroupCache) { - userGroupCache.Result.ClearCacheItem(RepositoryCacheKeys.GetKey(id)); - userGroupCache.Result.ClearCacheByKeySearch(UserGroupRepository.GetByAliasCacheKeyPrefix); + userGroupCache.Result.Clear(RepositoryCacheKeys.GetKey(id)); + userGroupCache.Result.ClearByKey(UserGroupRepository.GetByAliasCacheKeyPrefix); } //we don't know what user's belong to this group without doing a look up so we'll need to just clear them all diff --git a/src/Umbraco.Web/CacheHelperExtensions.cs b/src/Umbraco.Web/CacheHelperExtensions.cs index 3c5ea1930d..ae8df63415 100644 --- a/src/Umbraco.Web/CacheHelperExtensions.cs +++ b/src/Umbraco.Web/CacheHelperExtensions.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web /// public static void ClearPartialViewCache(this AppCaches appCaches) { - appCaches.RuntimeCache.ClearCacheByKeySearch(PartialViewCacheKey); + appCaches.RuntimeCache.ClearByKey(PartialViewCacheKey); } } } diff --git a/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs b/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs index f30f8e9745..5234bf9fa7 100644 --- a/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs +++ b/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.Dictionary public class DefaultCultureDictionary : Core.Dictionary.ICultureDictionary { private readonly ILocalizationService _localizationService; - private readonly ICacheProvider _requestCacheProvider; + private readonly IAppCache _requestCacheProvider; private readonly CultureInfo _specificCulture; public DefaultCultureDictionary() @@ -30,7 +30,7 @@ namespace Umbraco.Web.Dictionary } - public DefaultCultureDictionary(ILocalizationService localizationService, ICacheProvider requestCacheProvider) + public DefaultCultureDictionary(ILocalizationService localizationService, IAppCache requestCacheProvider) { _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); _requestCacheProvider = requestCacheProvider ?? throw new ArgumentNullException(nameof(requestCacheProvider)); @@ -42,7 +42,7 @@ namespace Umbraco.Web.Dictionary _specificCulture = specificCulture ?? throw new ArgumentNullException(nameof(specificCulture)); } - public DefaultCultureDictionary(CultureInfo specificCulture, ILocalizationService localizationService, ICacheProvider requestCacheProvider) + public DefaultCultureDictionary(CultureInfo specificCulture, ILocalizationService localizationService, IAppCache requestCacheProvider) { _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); _requestCacheProvider = requestCacheProvider ?? throw new ArgumentNullException(nameof(requestCacheProvider)); diff --git a/src/Umbraco.Web/Editors/ExamineManagementController.cs b/src/Umbraco.Web/Editors/ExamineManagementController.cs index b583babee3..db9de424a9 100644 --- a/src/Umbraco.Web/Editors/ExamineManagementController.cs +++ b/src/Umbraco.Web/Editors/ExamineManagementController.cs @@ -29,12 +29,12 @@ namespace Umbraco.Web.Editors { private readonly IExamineManager _examineManager; private readonly ILogger _logger; - private readonly IRuntimeCacheProvider _runtimeCacheProvider; + private readonly IAppPolicedCache _runtimeCacheProvider; private readonly IndexRebuilder _indexRebuilder; public ExamineManagementController(IExamineManager examineManager, ILogger logger, - IRuntimeCacheProvider runtimeCacheProvider, + IAppPolicedCache runtimeCacheProvider, IndexRebuilder indexRebuilder) { _examineManager = examineManager; @@ -114,7 +114,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(validate); var cacheKey = "temp_indexing_op_" + indexName; - var found = ApplicationCache.RuntimeCache.GetCacheItem(cacheKey); + var found = ApplicationCache.RuntimeCache.Get(cacheKey); //if its still there then it's not done return found != null @@ -153,7 +153,7 @@ namespace Umbraco.Web.Editors var cacheKey = "temp_indexing_op_" + index.Name; //put temp val in cache which is used as a rudimentary way to know when the indexing is done - ApplicationCache.RuntimeCache.InsertCacheItem(cacheKey, () => "tempValue", TimeSpan.FromMinutes(5)); + ApplicationCache.RuntimeCache.Insert(cacheKey, () => "tempValue", TimeSpan.FromMinutes(5)); _indexRebuilder.RebuildIndex(indexName); @@ -269,7 +269,7 @@ namespace Umbraco.Web.Editors >($"Rebuilding index '{indexer.Name}' done, {indexer.CommitCount} items committed (can differ from the number of items in the index)"); var cacheKey = "temp_indexing_op_" + indexer.Name; - _runtimeCacheProvider.ClearCacheItem(cacheKey); + _runtimeCacheProvider.Clear(cacheKey); } } } diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index e46e83c6e4..15cfda9ffd 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -63,7 +63,7 @@ namespace Umbraco.Web.Editors return await PostSetAvatarInternal(Request, Services.UserService, ApplicationCache.StaticCache, id); } - internal static async Task PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, ICacheProvider staticCache, int id) + internal static async Task PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, IAppCache staticCache, int id) { if (request.Content.IsMimeMultipartContent() == false) { diff --git a/src/Umbraco.Web/Macros/MacroRenderer.cs b/src/Umbraco.Web/Macros/MacroRenderer.cs index e0a0fd65c8..0bcdb3225b 100755 --- a/src/Umbraco.Web/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web/Macros/MacroRenderer.cs @@ -152,7 +152,7 @@ namespace Umbraco.Web.Macros macroContent.Date = DateTime.Now; var cache = Current.ApplicationCache.RuntimeCache; - cache.InsertCacheItem( + cache.Insert( CacheKeys.MacroContentCacheKey + model.CacheIdentifier, () => macroContent, new TimeSpan(0, 0, model.CacheDuration), diff --git a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs index 8261dda0d4..4b27af3120 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Models.Mapping => entity is ContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null; public UserMapperProfile(ILocalizedTextService textService, IUserService userService, IEntityService entityService, ISectionService sectionService, - IRuntimeCacheProvider runtimeCache, ActionCollection actions, IGlobalSettings globalSettings) + IAppPolicedCache runtimeCache, ActionCollection actions, IGlobalSettings globalSettings) { var userGroupDefaultPermissionsResolver = new UserGroupDefaultPermissionsResolver(textService, actions); diff --git a/src/Umbraco.Web/PublishedCache/IPublishedSnapshot.cs b/src/Umbraco.Web/PublishedCache/IPublishedSnapshot.cs index 0636eb808c..0865e61f08 100644 --- a/src/Umbraco.Web/PublishedCache/IPublishedSnapshot.cs +++ b/src/Umbraco.Web/PublishedCache/IPublishedSnapshot.cs @@ -36,7 +36,7 @@ namespace Umbraco.Web.PublishedCache /// /// The snapshot-level cache belongs to this snapshot only. /// - ICacheProvider SnapshotCache { get; } + IAppCache SnapshotCache { get; } /// /// Gets the elements-level cache. @@ -45,7 +45,7 @@ namespace Umbraco.Web.PublishedCache /// The elements-level cache is shared by all snapshots relying on the same elements, /// ie all snapshots built on top of unchanging content / media / etc. /// - ICacheProvider ElementsCache { get; } + IAppCache ElementsCache { get; } /// /// Forces the preview mode. diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs index 817c363fa5..566ab240c1 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs @@ -21,8 +21,8 @@ namespace Umbraco.Web.PublishedCache.NuCache internal class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable { private readonly ContentStore.Snapshot _snapshot; - private readonly ICacheProvider _snapshotCache; - private readonly ICacheProvider _elementsCache; + private readonly IAppCache _snapshotCache; + private readonly IAppCache _elementsCache; private readonly DomainHelper _domainHelper; private readonly IGlobalSettings _globalSettings; private readonly ILocalizationService _localizationService; @@ -34,7 +34,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // it's too late for UmbracoContext which has captured previewDefault and stuff into these ctor vars // but, no, UmbracoContext returns snapshot.Content which comes from elements SO a resync should create a new cache - public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, ICacheProvider snapshotCache, ICacheProvider elementsCache, DomainHelper domainHelper, IGlobalSettings globalSettings, ILocalizationService localizationService) + public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, DomainHelper domainHelper, IGlobalSettings globalSettings, ILocalizationService localizationService) : base(previewDefault) { _snapshot = snapshot; @@ -259,7 +259,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return GetAtRootNoCache(preview); // note: ToArray is important here, we want to cache the result, not the function! - return (IEnumerable)cache.GetCacheItem( + return (IEnumerable)cache.Get( CacheKeys.ContentCacheRoots(preview), () => GetAtRootNoCache(preview).ToArray()); } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs index f107b52a40..28c7c38c36 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs @@ -13,12 +13,12 @@ namespace Umbraco.Web.PublishedCache.NuCache internal class MediaCache : PublishedCacheBase, IPublishedMediaCache, INavigableData, IDisposable { private readonly ContentStore.Snapshot _snapshot; - private readonly ICacheProvider _snapshotCache; - private readonly ICacheProvider _elementsCache; + private readonly IAppCache _snapshotCache; + private readonly IAppCache _elementsCache; #region Constructors - public MediaCache(bool previewDefault, ContentStore.Snapshot snapshot, ICacheProvider snapshotCache, ICacheProvider elementsCache) + public MediaCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache) : base(previewDefault) { _snapshot = snapshot; @@ -63,7 +63,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return GetAtRootNoCache(); // note: ToArray is important here, we want to cache the result, not the function! - return (IEnumerable)cache.GetCacheItem( + return (IEnumerable)cache.Get( CacheKeys.MediaCacheRoots(false), // ignore preview, only 1 key! () => GetAtRootNoCache().ToArray()); } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs index f2392c9c3d..ecf099f90b 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs @@ -19,12 +19,12 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; public readonly IVariationContextAccessor VariationContextAccessor; private readonly IEntityXmlSerializer _entitySerializer; - private readonly ICacheProvider _snapshotCache; + private readonly IAppCache _snapshotCache; private readonly IMemberService _memberService; private readonly PublishedContentTypeCache _contentTypeCache; private readonly bool _previewDefault; - public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer) + public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer) { _snapshotCache = snapshotCache; _publishedSnapshotAccessor = publishedSnapshotAccessor; diff --git a/src/Umbraco.Web/PublishedCache/NuCache/Property.cs b/src/Umbraco.Web/PublishedCache/NuCache/Property.cs index 132c4b6d59..2c8bc94d90 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/Property.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/Property.cs @@ -125,7 +125,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { CacheValues cacheValues; PublishedSnapshot publishedSnapshot; - ICacheProvider cache; + IAppCache cache; switch (cacheLevel) { case PropertyCacheLevel.None: @@ -161,11 +161,11 @@ namespace Umbraco.Web.PublishedCache.NuCache return cacheValues; } - private CacheValues GetCacheValues(ICacheProvider cache) + private CacheValues GetCacheValues(IAppCache cache) { if (cache == null) // no cache, don't cache return new CacheValues(); - return (CacheValues) cache.GetCacheItem(ValuesCacheKey, () => new CacheValues()); + return (CacheValues) cache.Get(ValuesCacheKey, () => new CacheValues()); } // this is always invoked from within a lock, so does not require its own lock diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index 25e5244d32..65b7a1560a 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -48,7 +48,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var cache = GetCurrentSnapshotCache(); return cache == null ? GetProfileNameByIdNoCache(id) - : (string)cache.GetCacheItem(CacheKeys.ProfileName(id), () => GetProfileNameByIdNoCache(id)); + : (string)cache.Get(CacheKeys.ProfileName(id), () => GetProfileNameByIdNoCache(id)); } private static string GetProfileNameByIdNoCache(int id) @@ -328,7 +328,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return GetChildren(); // note: ToArray is important here, we want to cache the result, not the function! - return (IEnumerable)cache.GetCacheItem(ChildrenCacheKey, () => GetChildren().ToArray()); + return (IEnumerable)cache.Get(ChildrenCacheKey, () => GetChildren().ToArray()); } } @@ -383,7 +383,7 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Caching // beware what you use that one for - you don't want to cache its result - private ICacheProvider GetAppropriateCache() + private IAppCache GetAppropriateCache() { var publishedSnapshot = (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot; var cache = publishedSnapshot == null @@ -394,7 +394,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return cache; } - private ICacheProvider GetCurrentSnapshotCache() + private IAppCache GetCurrentSnapshotCache() { var publishedSnapshot = (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot; return publishedSnapshot?.SnapshotCache; @@ -436,7 +436,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var cache = GetAppropriateCache(); if (cache == null) return new PublishedContent(this).CreateModel(); - return (IPublishedContent)cache.GetCacheItem(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel()); + return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel()); } // used by Navigable.Source,... diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshot.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshot.cs index 9b8982c69c..2ceced75eb 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshot.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshot.cs @@ -25,8 +25,8 @@ namespace Umbraco.Web.PublishedCache.NuCache public MediaCache MediaCache; public MemberCache MemberCache; public DomainCache DomainCache; - public ICacheProvider SnapshotCache; - public ICacheProvider ElementsCache; + public IAppCache SnapshotCache; + public IAppCache ElementsCache; public void Dispose() { @@ -48,9 +48,9 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Caches - public ICacheProvider SnapshotCache => Elements.SnapshotCache; + public IAppCache SnapshotCache => Elements.SnapshotCache; - public ICacheProvider ElementsCache => Elements.ElementsCache; + public IAppCache ElementsCache => Elements.ElementsCache; #endregion diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 36f3472c31..bcb1c6ede3 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -932,7 +932,7 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Create, Get Published Snapshot private long _contentGen, _mediaGen, _domainGen; - private ICacheProvider _elementsCache; + private IAppCache _elementsCache; public override IPublishedSnapshot CreatePublishedSnapshot(string previewToken) { @@ -960,7 +960,7 @@ namespace Umbraco.Web.PublishedCache.NuCache ContentStore.Snapshot contentSnap, mediaSnap; SnapDictionary.Snapshot domainSnap; - ICacheProvider elementsCache; + IAppCache elementsCache; lock (_storesLock) { var scopeContext = _scopeProvider.Context; @@ -998,11 +998,11 @@ namespace Umbraco.Web.PublishedCache.NuCache _contentGen = contentSnap.Gen; _mediaGen = mediaSnap.Gen; _domainGen = domainSnap.Gen; - elementsCache = _elementsCache = new DictionaryCacheProvider(); + elementsCache = _elementsCache = new FastDictionaryCacheProvider(); } } - var snapshotCache = new StaticCacheProvider(); + var snapshotCache = new DictionaryCacheProvider(); var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _publishedContentTypeFactory, _logger); diff --git a/src/Umbraco.Web/PublishedCache/PublishedElementPropertyBase.cs b/src/Umbraco.Web/PublishedCache/PublishedElementPropertyBase.cs index cff1e40b69..6d69b96e0c 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedElementPropertyBase.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedElementPropertyBase.cs @@ -106,7 +106,7 @@ namespace Umbraco.Web.PublishedCache } } - private ICacheProvider GetSnapshotCache() + private IAppCache GetSnapshotCache() { // cache within the snapshot cache, unless previewing, then use the snapshot or // elements cache (if we don't want to pollute the elements cache with short-lived @@ -135,12 +135,12 @@ namespace Umbraco.Web.PublishedCache case PropertyCacheLevel.Elements: // cache within the elements cache, depending... var snapshotCache = GetSnapshotCache(); - cacheValues = (CacheValues) snapshotCache?.GetCacheItem(ValuesCacheKey, () => new CacheValues()) ?? new CacheValues(); + cacheValues = (CacheValues) snapshotCache?.Get(ValuesCacheKey, () => new CacheValues()) ?? new CacheValues(); break; case PropertyCacheLevel.Snapshot: // cache within the snapshot cache var facadeCache = _publishedSnapshotAccessor?.PublishedSnapshot?.SnapshotCache; - cacheValues = (CacheValues) facadeCache?.GetCacheItem(ValuesCacheKey, () => new CacheValues()) ?? new CacheValues(); + cacheValues = (CacheValues) facadeCache?.Get(ValuesCacheKey, () => new CacheValues()) ?? new CacheValues(); break; default: throw new InvalidOperationException("Invalid cache level."); diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index 6f6a39144a..ea38af314f 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -35,7 +35,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache Func getParent, Func> getChildren, Func getProperty, - ICacheProvider cacheProvider, + IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache, XPathNavigator nav, bool fromExamine) @@ -133,7 +133,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache //private readonly Func> _getChildren; private readonly Lazy> _getChildren; private readonly Func _getProperty; - private readonly ICacheProvider _cacheProvider; + private readonly IAppCache _cacheProvider; /// /// Returns 'Media' as the item type diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index e022e36fc0..67813ce9f6 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -15,7 +15,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { internal class PublishedContentCache : PublishedCacheBase, IPublishedContentCache { - private readonly ICacheProvider _cacheProvider; + private readonly IAppCache _cacheProvider; private readonly IGlobalSettings _globalSettings; private readonly RoutesCache _routesCache; private readonly IDomainCache _domainCache; @@ -30,7 +30,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public PublishedContentCache( XmlStore xmlStore, // an XmlStore containing the master xml IDomainCache domainCache, // an IDomainCache implementation - ICacheProvider cacheProvider, // an ICacheProvider that should be at request-level + IAppCache cacheProvider, // an ICacheProvider that should be at request-level IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, PublishedContentTypeCache contentTypeCache, // a PublishedContentType cache @@ -517,7 +517,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // clear recursive properties cached by XmlPublishedContent.GetProperty // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch) // NOTE also clears all the media cache properties, which is OK (see media cache) - _cacheProvider.ClearCacheObjectTypes(); + _cacheProvider.ClearOfType(); //_cacheProvider.ClearCacheByKeySearch("XmlPublishedCache.PublishedContentCache:RecursiveProperty-"); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index 09b76b5c2e..3ead5a5166 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -43,9 +43,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IEntityXmlSerializer _entitySerializer; // must be specified by the ctor - private readonly ICacheProvider _cacheProvider; + private readonly IAppCache _cacheProvider; - public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) + public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); @@ -66,7 +66,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// /// /// - internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) + internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); @@ -678,7 +678,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var cache = Current.ApplicationCache.RuntimeCache; var key = PublishedMediaCacheKey + id; - return (CacheValues)cache.GetCacheItem(key, () => func(id), _publishedMediaCacheTimespan); + return (CacheValues)cache.Get(key, () => func(id), _publishedMediaCacheTimespan); } internal static void ClearCache(int id) @@ -696,11 +696,11 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // cache.ClearCacheItem(PublishedMediaCacheKey + GetValuesValue(exist.Values, "parentID")); // clear the item - cache.ClearCacheItem(key); + cache.Clear(key); // clear all children - in case we moved and their path has changed var fid = "/" + sid + "/"; - cache.ClearCacheObjectTypes((k, v) => + cache.ClearOfType((k, v) => GetValuesValue(v.Values, "path", "__Path").Contains(fid)); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs index 2328a1cefd..a622a4934c 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs @@ -13,11 +13,11 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache class PublishedMemberCache : IPublishedMemberCache { private readonly IMemberService _memberService; - private readonly ICacheProvider _requestCache; + private readonly IAppCache _requestCache; private readonly XmlStore _xmlStore; private readonly PublishedContentTypeCache _contentTypeCache; - public PublishedMemberCache(XmlStore xmlStore, ICacheProvider requestCacheProvider, IMemberService memberService, PublishedContentTypeCache contentTypeCache) + public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCacheProvider, IMemberService memberService, PublishedContentTypeCache contentTypeCache) { _requestCache = requestCacheProvider; _memberService = memberService; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshot.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshot.cs index 61ea7d2534..b9243309a2 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshot.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshot.cs @@ -38,10 +38,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public IDomainCache Domains { get; } /// - public ICacheProvider SnapshotCache => null; + public IAppCache SnapshotCache => null; /// - public ICacheProvider ElementsCache => null; + public IAppCache ElementsCache => null; /// public IDisposable ForcedPreview(bool preview, Action callback = null) diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs index e286e9d95c..c4ce05c9a9 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs @@ -30,7 +30,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IMemberService _memberService; private readonly IMediaService _mediaService; private readonly IUserService _userService; - private readonly ICacheProvider _requestCache; + private readonly IAppCache _requestCache; private readonly IGlobalSettings _globalSettings; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly ISiteDomainHelper _siteDomainHelper; @@ -42,7 +42,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public PublishedSnapshotService(ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IScopeProvider scopeProvider, - ICacheProvider requestCache, + IAppCache requestCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, @@ -63,7 +63,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache internal PublishedSnapshotService(ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IScopeProvider scopeProvider, - ICacheProvider requestCache, + IAppCache requestCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index efd4535bd4..a1fda17df1 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache [XmlType(Namespace = "http://umbraco.org/webservices/")] internal class XmlPublishedContent : PublishedContentBase { - private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache) + private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache) { _xmlNode = xmlNode; _isPreviewing = isPreviewing; @@ -31,7 +31,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly XmlNode _xmlNode; private readonly bool _isPreviewing; - private readonly ICacheProvider _cacheProvider; // at snapshot/request level (see PublishedContentCache) + private readonly IAppCache _cacheProvider; // at snapshot/request level (see PublishedContentCache) private readonly PublishedContentTypeCache _contentTypeCache; private readonly object _initializeLock = new object(); @@ -426,7 +426,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// Maintains a per-request cache of IPublishedContent items in order to make /// sure that we create only one instance of each for the duration of a request. The /// returned IPublishedContent is a model, if models are enabled. - public static IPublishedContent Get(XmlNode node, bool isPreviewing, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache) + public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache) { // only 1 per request @@ -434,12 +434,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var id = attrs?.GetNamedItem("id").Value; if (id.IsNullOrWhiteSpace()) throw new InvalidOperationException("Node has no ID attribute."); var key = CacheKeyPrefix + id; // dont bother with preview, wont change during request in Xml cache - return (IPublishedContent) cacheProvider.GetCacheItem(key, () => (new XmlPublishedContent(node, isPreviewing, cacheProvider, contentTypeCache)).CreateModel()); + return (IPublishedContent) cacheProvider.Get(key, () => (new XmlPublishedContent(node, isPreviewing, cacheProvider, contentTypeCache)).CreateModel()); } public static void ClearRequest() { - Current.ApplicationCache.RequestCache.ClearCacheByKeySearch(CacheKeyPrefix); + Current.ApplicationCache.RequestCache.ClearByKey(CacheKeyPrefix); } private const string CacheKeyPrefix = "CONTENTCACHE_XMLPUBLISHEDCONTENT_"; diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Web/Runtime/WebRuntime.cs index c69a3bec8b..e9d27a2a1c 100644 --- a/src/Umbraco.Web/Runtime/WebRuntime.cs +++ b/src/Umbraco.Web/Runtime/WebRuntime.cs @@ -62,14 +62,14 @@ namespace Umbraco.Web.Runtime protected override AppCaches GetAppCaches() => new AppCaches( // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) - new DeepCloneRuntimeCacheProvider(new HttpRuntimeCacheProvider(HttpRuntime.Cache)), - new StaticCacheProvider(), + new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache)), + new DictionaryCacheProvider(), // we need request based cache when running in web-based context - new HttpRequestCacheProvider(), - new IsolatedRuntimeCache(type => + new HttpRequestAppCache(), + new IsolatedCaches(type => // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) - new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))); + new DeepCloneAppCache(new ObjectCacheAppCache()))); #endregion } diff --git a/src/Umbraco.Web/Services/ApplicationTreeService.cs b/src/Umbraco.Web/Services/ApplicationTreeService.cs index 2ddec054c7..30d50e136c 100644 --- a/src/Umbraco.Web/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Web/Services/ApplicationTreeService.cs @@ -357,7 +357,7 @@ namespace Umbraco.Web.Services //remove the cache now that it has changed SD: I'm leaving this here even though it // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + _cache.RuntimeCache.Clear(CacheKeys.ApplicationTreeCacheKey); } } } diff --git a/src/Umbraco.Web/Services/SectionService.cs b/src/Umbraco.Web/Services/SectionService.cs index 2d06141292..09972a6dca 100644 --- a/src/Umbraco.Web/Services/SectionService.cs +++ b/src/Umbraco.Web/Services/SectionService.cs @@ -132,7 +132,7 @@ namespace Umbraco.Web.Services //remove the cache so it gets re-read ... SD: I'm leaving this here even though it // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + _cache.RuntimeCache.Clear(CacheKeys.ApplicationsCacheKey); } } } From d4c714eccd0a6097865998ca9d01ba39e4898517 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 17 Jan 2019 11:19:06 +0100 Subject: [PATCH 156/223] Stop injecting the runtime cache, use AppCaches --- src/Umbraco.Core/Cache/ObjectCacheAppCache.cs | 2 +- .../Composing/Composers/ServicesComposer.cs | 2 +- .../Composing/CompositionExtensions.cs | 1 - src/Umbraco.Core/ConfigsExtensions.cs | 4 ++-- .../Configuration/Grid/GridConfig.cs | 4 ++-- .../Configuration/Grid/GridEditorsConfig.cs | 10 +++++----- src/Umbraco.Core/Manifest/ManifestParser.cs | 9 +++++---- .../Implement/DictionaryRepository.cs | 4 ++-- .../Implement/RepositoryBaseOfTIdTEntity.cs | 12 ++++++------ .../Implement/ServerRegistrationRepository.cs | 2 +- src/Umbraco.Core/Runtime/CoreRuntime.cs | 3 +-- .../LocalizedTextServiceFileSources.cs | 17 ++++++----------- .../Manifest/ManifestParserTests.cs | 2 +- .../Models/Mapping/AutoMapperTests.cs | 2 +- .../Scoping/ScopedRepositoryTests.cs | 2 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 2 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 9 ++++----- .../Editors/ExamineManagementController.cs | 15 ++++----------- .../Models/Mapping/UserMapperProfile.cs | 8 ++++---- 19 files changed, 48 insertions(+), 62 deletions(-) diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs index 9c5917a53c..954622fc4b 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs @@ -31,7 +31,7 @@ namespace Umbraco.Core.Cache /// /// Gets the internal memory cache, for tests only! /// - internal readonly ObjectCache MemoryCache; + internal ObjectCache MemoryCache { get; private set; } /// public object Get(string key) diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index 9ed4a7265c..2af7c5a011 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -116,7 +116,7 @@ namespace Umbraco.Core.Composing.Composers return new LocalizedTextServiceFileSources( container.GetInstance(), - container.GetInstance().RuntimeCache, + container.GetInstance(), mainLangFolder, pluginLangFolders.Concat(userLangFolders)); } diff --git a/src/Umbraco.Core/Composing/CompositionExtensions.cs b/src/Umbraco.Core/Composing/CompositionExtensions.cs index 910062688c..c312259b82 100644 --- a/src/Umbraco.Core/Composing/CompositionExtensions.cs +++ b/src/Umbraco.Core/Composing/CompositionExtensions.cs @@ -28,7 +28,6 @@ namespace Umbraco.Core.Composing composition.RegisterUnique(profilingLogger); composition.RegisterUnique(mainDom); composition.RegisterUnique(appCaches); - composition.RegisterUnique(factory => factory.GetInstance().RuntimeCache); composition.RegisterUnique(databaseFactory); composition.RegisterUnique(factory => factory.GetInstance().SqlContext); composition.RegisterUnique(typeLoader); diff --git a/src/Umbraco.Core/ConfigsExtensions.cs b/src/Umbraco.Core/ConfigsExtensions.cs index 9b2abda53c..0fcea5f430 100644 --- a/src/Umbraco.Core/ConfigsExtensions.cs +++ b/src/Umbraco.Core/ConfigsExtensions.cs @@ -46,7 +46,7 @@ namespace Umbraco.Core configs.Add(() => new CoreDebug()); // GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition - configs.Add(factory => new GridConfig(factory.GetInstance(), factory.GetInstance(), configDir, factory.GetInstance().Debug)); + configs.Add(factory => new GridConfig(factory.GetInstance(), factory.GetInstance(), configDir, factory.GetInstance().Debug)); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs index 979eccb839..b2dae09fc9 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -6,9 +6,9 @@ namespace Umbraco.Core.Configuration.Grid { class GridConfig : IGridConfig { - public GridConfig(ILogger logger, IAppPolicedCache runtimeCache, DirectoryInfo configFolder, bool isDebug) + public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, bool isDebug) { - EditorsConfig = new GridEditorsConfig(logger, runtimeCache, configFolder, isDebug); + EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, isDebug); } public IGridEditorsConfig EditorsConfig { get; } diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs index 121b74194c..e2f99a753b 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -13,14 +13,14 @@ namespace Umbraco.Core.Configuration.Grid internal class GridEditorsConfig : IGridEditorsConfig { private readonly ILogger _logger; - private readonly IAppPolicedCache _runtimeCache; + private readonly AppCaches _appCaches; private readonly DirectoryInfo _configFolder; private readonly bool _isDebug; - public GridEditorsConfig(ILogger logger, IAppPolicedCache runtimeCache, DirectoryInfo configFolder, bool isDebug) + public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, bool isDebug) { _logger = logger; - _runtimeCache = runtimeCache; + _appCaches = appCaches; _configFolder = configFolder; _isDebug = isDebug; } @@ -32,7 +32,7 @@ namespace Umbraco.Core.Configuration.Grid List GetResult() { // fixme - should use the common one somehow! + ignoring _appPlugins here! - var parser = new ManifestParser(_runtimeCache, Current.ManifestValidators, _logger); + var parser = new ManifestParser(_appCaches, Current.ManifestValidators, _logger); var editors = new List(); var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js"); @@ -62,7 +62,7 @@ namespace Umbraco.Core.Configuration.Grid //cache the result if debugging is disabled var result = _isDebug ? GetResult() - : _runtimeCache.GetCacheItem>(typeof(GridEditorsConfig) + ".Editors",GetResult, TimeSpan.FromMinutes(10)); + : _appCaches.RuntimeCache.GetCacheItem>(typeof(GridEditorsConfig) + ".Editors",GetResult, TimeSpan.FromMinutes(10)); return result; } diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index fd344674af..40e99bb079 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -29,16 +29,17 @@ namespace Umbraco.Core.Manifest /// /// Initializes a new instance of the class. /// - public ManifestParser(IAppPolicedCache cache, ManifestValueValidatorCollection validators, ILogger logger) - : this(cache, validators, "~/App_Plugins", logger) + public ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ILogger logger) + : this(appCaches, validators, "~/App_Plugins", logger) { } /// /// Initializes a new instance of the class. /// - private ManifestParser(IAppPolicedCache cache, ManifestValueValidatorCollection validators, string path, ILogger logger) + private ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, string path, ILogger logger) { - _cache = cache ?? throw new ArgumentNullException(nameof(cache)); + if (appCaches == null) throw new ArgumentNullException(nameof(appCaches)); + _cache = appCaches.RuntimeCache; _validators = validators ?? throw new ArgumentNullException(nameof(validators)); if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullOrEmptyException(nameof(path)); Path = path; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs index 9b191d830c..be1e28fcc1 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -224,13 +224,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public IDictionaryItem Get(Guid uniqueId) { - var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, ScopeAccessor, GlobalCache, Logger); + var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, ScopeAccessor, AppCaches, Logger); return uniqueIdRepo.Get(uniqueId); } public IDictionaryItem Get(string key) { - var keyRepo = new DictionaryByKeyRepository(this, ScopeAccessor, GlobalCache, Logger); + var keyRepo = new DictionaryByKeyRepository(this, ScopeAccessor, AppCaches, Logger); return keyRepo.Get(key); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index f106949c77..6862173786 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -19,18 +19,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private IRepositoryCachePolicy _cachePolicy; - protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger) { ScopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - GlobalCache = cache ?? throw new ArgumentNullException(nameof(cache)); + AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); } protected ILogger Logger { get; } - protected AppCaches GlobalCache { get; } + protected AppCaches AppCaches { get; } - protected IAppPolicedCache GlobalIsolatedCache => GlobalCache.IsolatedCaches.GetOrCreate(); + protected IAppPolicedCache GlobalIsolatedCache => AppCaches.IsolatedCaches.GetOrCreate(); protected IScopeAccessor ScopeAccessor { get; } @@ -67,7 +67,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement switch (AmbientScope.RepositoryCacheMode) { case RepositoryCacheMode.Default: - return GlobalCache.IsolatedCaches.GetOrCreate(); + return AppCaches.IsolatedCaches.GetOrCreate(); case RepositoryCacheMode.Scoped: return AmbientScope.IsolatedCaches.GetOrCreate(); case RepositoryCacheMode.None: @@ -127,7 +127,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { get { - if (GlobalCache == AppCaches.NoCache) + if (AppCaches == AppCaches.NoCache) return NoCacheRepositoryCachePolicy.Instance; // create the cache policy using IsolatedCache which is either global diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index ead7c066be..298e503736 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -28,7 +28,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // and this is because the repository is special and should not participate in scopes // (cleanup in v8) // - return new FullDataSetRepositoryCachePolicy(GlobalCache.RuntimeCache, ScopeAccessor, GetEntityId, /*expires:*/ false); + return new FullDataSetRepositoryCachePolicy(AppCaches.RuntimeCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } public void ClearCache() diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index e37b5e254e..6bfe9cdb55 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -102,7 +102,6 @@ namespace Umbraco.Core.Runtime // application caches var appCaches = GetAppCaches(); - var runtimeCache = appCaches.RuntimeCache; // database factory var databaseFactory = GetDatabaseFactory(); @@ -112,7 +111,7 @@ namespace Umbraco.Core.Runtime // type loader var localTempStorage = configs.Global().LocalTempStorageLocation; - var typeLoader = new TypeLoader(runtimeCache, localTempStorage, ProfilingLogger); + var typeLoader = new TypeLoader(appCaches.RuntimeCache, localTempStorage, ProfilingLogger); // runtime state // beware! must use '() => _factory.GetInstance()' and NOT '_factory.GetInstance' diff --git a/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs b/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs index 5577508adb..8c2d277348 100644 --- a/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs +++ b/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs @@ -37,16 +37,16 @@ namespace Umbraco.Core.Services.Implement /// public LocalizedTextServiceFileSources( ILogger logger, - IAppPolicedCache cache, + AppCaches appCaches, DirectoryInfo fileSourceFolder, IEnumerable supplementFileSources) { if (logger == null) throw new ArgumentNullException("logger"); - if (cache == null) throw new ArgumentNullException("cache"); + if (appCaches == null) throw new ArgumentNullException("cache"); if (fileSourceFolder == null) throw new ArgumentNullException("fileSourceFolder"); _logger = logger; - _cache = cache; + _cache = appCaches.RuntimeCache; //Create the lazy source for the _xmlSources _xmlSources = new Lazy>>(() => @@ -137,14 +137,9 @@ namespace Umbraco.Core.Services.Implement /// /// Constructor /// - /// - /// - /// - public LocalizedTextServiceFileSources(ILogger logger, IAppPolicedCache cache, DirectoryInfo fileSourceFolder) - : this(logger, cache, fileSourceFolder, Enumerable.Empty()) - { - - } + public LocalizedTextServiceFileSources(ILogger logger, AppCaches appCaches, DirectoryInfo fileSourceFolder) + : this(logger, appCaches, fileSourceFolder, Enumerable.Empty()) + { } /// /// returns all xml sources for all culture files found in the folder diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs index 74f9fd7157..3f1e668dc0 100644 --- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs @@ -44,7 +44,7 @@ namespace Umbraco.Tests.Manifest new RequiredValidator(Mock.Of()), new RegexValidator(Mock.Of(), null) }; - _parser = new ManifestParser(NoAppCache.Instance, new ManifestValueValidatorCollection(validators), Mock.Of()); + _parser = new ManifestParser(AppCaches.Disabled, new ManifestValueValidatorCollection(validators), Mock.Of()); } [Test] diff --git a/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs b/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs index f48abc1233..57d38e342e 100644 --- a/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs @@ -20,7 +20,7 @@ namespace Umbraco.Tests.Models.Mapping base.Compose(); var manifestBuilder = new ManifestParser( - AppCaches.Disabled.RuntimeCache, + AppCaches.Disabled, new ManifestValueValidatorCollection(Enumerable.Empty()), Composition.Logger) { diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index 6e01de1670..12cd02d2e9 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests.Scoping .Add(() => Composition.TypeLoader.GetCacheRefreshers()); } - protected override AppCaches GetCacheHelper() + protected override AppCaches GetAppCaches() { // this is what's created core web runtime return new AppCaches( diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 29eb649c48..34c97fcea2 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -140,7 +140,7 @@ namespace Umbraco.Tests.TestHelpers return new LocalizedTextServiceFileSources( logger, - cache.RuntimeCache, + cache, mainLangFolder, pluginLangFolders.Concat(userLangFolders)); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 2d6e01b6bb..fd617b5a21 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -125,9 +125,9 @@ namespace Umbraco.Tests.Testing var (logger, profiler) = GetLoggers(Options.Logger); var proflogger = new ProfilingLogger(logger, profiler); - var cacheHelper = GetCacheHelper(); + var appCaches = GetAppCaches(); var globalSettings = SettingsForTests.GetDefaultGlobalSettings(); - var typeLoader = GetTypeLoader(cacheHelper.RuntimeCache, globalSettings, proflogger, Options.TypeLoader); + var typeLoader = GetTypeLoader(appCaches.RuntimeCache, globalSettings, proflogger, Options.TypeLoader); var register = RegisterFactory.Create(); @@ -137,8 +137,7 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(logger); Composition.RegisterUnique(profiler); Composition.RegisterUnique(proflogger); - Composition.RegisterUnique(cacheHelper); - Composition.RegisterUnique(cacheHelper.RuntimeCache); + Composition.RegisterUnique(appCaches); TestObjects = new TestObjects(register); Compose(); @@ -199,7 +198,7 @@ namespace Umbraco.Tests.Testing return (logger, profiler); } - protected virtual AppCaches GetCacheHelper() + protected virtual AppCaches GetAppCaches() { return AppCaches.Disabled; } diff --git a/src/Umbraco.Web/Editors/ExamineManagementController.cs b/src/Umbraco.Web/Editors/ExamineManagementController.cs index db9de424a9..8d930b8ed7 100644 --- a/src/Umbraco.Web/Editors/ExamineManagementController.cs +++ b/src/Umbraco.Web/Editors/ExamineManagementController.cs @@ -1,26 +1,19 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Net; using System.Net.Http; -using System.Reflection; using System.Web.Http; using Examine; -using Examine.LuceneEngine; using Examine.LuceneEngine.Providers; -using Lucene.Net.Analysis; -using Lucene.Net.QueryParsers; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Examine; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.Search; using SearchResult = Umbraco.Web.Models.ContentEditing.SearchResult; -using Version = Lucene.Net.Util.Version; namespace Umbraco.Web.Editors { @@ -29,17 +22,17 @@ namespace Umbraco.Web.Editors { private readonly IExamineManager _examineManager; private readonly ILogger _logger; - private readonly IAppPolicedCache _runtimeCacheProvider; + private readonly IAppPolicedCache _runtimeCache; private readonly IndexRebuilder _indexRebuilder; public ExamineManagementController(IExamineManager examineManager, ILogger logger, - IAppPolicedCache runtimeCacheProvider, + AppCaches appCaches, IndexRebuilder indexRebuilder) { _examineManager = examineManager; _logger = logger; - _runtimeCacheProvider = runtimeCacheProvider; + _runtimeCache = appCaches.RuntimeCache; _indexRebuilder = indexRebuilder; } @@ -269,7 +262,7 @@ namespace Umbraco.Web.Editors >($"Rebuilding index '{indexer.Name}' done, {indexer.CommitCount} items committed (can differ from the number of items in the index)"); var cacheKey = "temp_indexing_op_" + indexer.Name; - _runtimeCacheProvider.Clear(cacheKey); + _runtimeCache.Clear(cacheKey); } } } diff --git a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs index 4b27af3120..b6fc94eb3c 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Models.Mapping => entity is ContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null; public UserMapperProfile(ILocalizedTextService textService, IUserService userService, IEntityService entityService, ISectionService sectionService, - IAppPolicedCache runtimeCache, ActionCollection actions, IGlobalSettings globalSettings) + AppCaches appCaches, ActionCollection actions, IGlobalSettings globalSettings) { var userGroupDefaultPermissionsResolver = new UserGroupDefaultPermissionsResolver(textService, actions); @@ -243,7 +243,7 @@ namespace Umbraco.Web.Models.Mapping //Important! Currently we are never mapping to multiple UserDisplay objects but if we start doing that // this will cause an N+1 and we'll need to change how this works. CreateMap() - .ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetUserAvatarUrls(runtimeCache))) + .ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetUserAvatarUrls(appCaches.RuntimeCache))) .ForMember(dest => dest.Username, opt => opt.MapFrom(user => user.Username)) .ForMember(dest => dest.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate)) .ForMember(dest => dest.UserGroups, opt => opt.MapFrom(user => user.Groups)) @@ -293,7 +293,7 @@ namespace Umbraco.Web.Models.Mapping //like the load time is waiting. .ForMember(detail => detail.Avatars, - opt => opt.MapFrom(user => user.GetUserAvatarUrls(runtimeCache))) + opt => opt.MapFrom(user => user.GetUserAvatarUrls(appCaches.RuntimeCache))) .ForMember(dest => dest.Username, opt => opt.MapFrom(user => user.Username)) .ForMember(dest => dest.UserGroups, opt => opt.MapFrom(user => user.Groups)) .ForMember(dest => dest.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate)) @@ -313,7 +313,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); CreateMap() - .ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetUserAvatarUrls(runtimeCache))) + .ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetUserAvatarUrls(appCaches.RuntimeCache))) .ForMember(dest => dest.UserId, opt => opt.MapFrom(user => GetIntId(user.Id))) .ForMember(dest => dest.StartContentIds, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(entityService))) .ForMember(dest => dest.StartMediaIds, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(entityService))) From 0d0179cb476450b4c580efb95f5c6b785270e3e1 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 17 Jan 2019 12:14:17 +0100 Subject: [PATCH 157/223] Use constants in upgrade migration --- .../UpdateMemberGroupPickerData.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs index 2dbc69e58a..62cbeacc78 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs @@ -16,17 +16,17 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourtee public override void Up() { // move the data for all member group properties from the NVarchar to the NText column and clear the NVarchar column - Execute.Sql(@"UPDATE cmsPropertyData SET dataNtext = dataNvarchar, dataNvarchar = NULL + Execute.Sql($@"UPDATE cmsPropertyData SET dataNtext = dataNvarchar, dataNvarchar = NULL WHERE dataNtext IS NULL AND id IN ( SELECT id FROM cmsPropertyData WHERE propertyTypeId in ( SELECT id from cmsPropertyType where dataTypeID IN ( - SELECT nodeId FROM cmsDataType WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker' + SELECT nodeId FROM cmsDataType WHERE propertyEditorAlias = '{Constants.PropertyEditors.MemberGroupPickerAlias}' ) ) )"); // ensure that all exising member group properties are defined as NText - Execute.Sql("UPDATE cmsDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker'"); + Execute.Sql($"UPDATE cmsDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = '{Constants.PropertyEditors.MemberGroupPickerAlias}'"); } public override void Down() From 77cf071e046dc54adb92194537d9b221d28eda5f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 17 Jan 2019 12:20:13 +0100 Subject: [PATCH 158/223] Add "Move" option for deleted items in the media tree (#3914) --- .../views/media/media.restore.controller.js | 135 +++++++++++++----- .../src/views/media/restore.html | 97 +++++++++++-- 2 files changed, 187 insertions(+), 45 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/media/media.restore.controller.js b/src/Umbraco.Web.UI.Client/src/views/media/media.restore.controller.js index 6ef9232c37..bc02217660 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/media.restore.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/media/media.restore.controller.js @@ -1,63 +1,134 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController", - function ($scope, relationResource, mediaResource, navigationService, appState, treeService, localizationService) { + function ($scope, relationResource, mediaResource, navigationService, appState, treeService, userService) { var dialogOptions = $scope.dialogOptions; - var node = dialogOptions.currentNode; + $scope.source = _.clone(dialogOptions.currentNode); - $scope.error = null; - $scope.success = false; + $scope.error = null; + $scope.loading = true; + $scope.moving = false; + $scope.success = false; - relationResource.getByChildId(node.id, "relateParentDocumentOnDelete").then(function (data) { + $scope.dialogTreeEventHandler = $({}); + $scope.searchInfo = { + showSearch: false, + results: [], + selectedSearchResults: [] + } + $scope.treeModel = { + hideHeader: false + } + userService.getCurrentUser().then(function (userData) { + $scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1; + }); - if (data.length == 0) { - $scope.success = false; - $scope.error = { - errorMsg: localizationService.localize('recycleBin_itemCannotBeRestored'), - data: { - Message: localizationService.localize('recycleBin_noRestoreRelation') - } - } - return; + function nodeSelectHandler(ev, args) { + + if (args && args.event) { + args.event.preventDefault(); + args.event.stopPropagation(); } + if ($scope.target) { + //un-select if there's a current one selected + $scope.target.selected = false; + } + + $scope.target = args.node; + $scope.target.selected = true; + + } + + function nodeExpandedHandler(ev, args) { + // open mini list view for list views + if (args.node.metaData.isContainer) { + openMiniListView(args.node); + } + } + + $scope.hideSearch = function () { + $scope.searchInfo.showSearch = false; + $scope.searchInfo.results = []; + } + + // method to select a search result + $scope.selectResult = function (evt, result) { + result.selected = result.selected === true ? false : true; + nodeSelectHandler(evt, { event: evt, node: result }); + }; + + //callback when there are search results + $scope.onSearchResults = function (results) { + $scope.searchInfo.results = results; + $scope.searchInfo.showSearch = true; + }; + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler); + }); + + // Mini list view + $scope.selectListViewNode = function (node) { + node.selected = node.selected === true ? false : true; + nodeSelectHandler({}, { node: node }); + }; + + $scope.closeMiniListView = function () { + $scope.miniListView = undefined; + }; + + function openMiniListView(node) { + $scope.miniListView = node; + } + + relationResource.getByChildId($scope.source.id, "relateParentDocumentOnDelete").then(function (data) { + $scope.loading = false; + + if (!data.length) { + $scope.moving = true; + return; + } + $scope.relation = data[0]; if ($scope.relation.parentId == -1) { $scope.target = { id: -1, name: "Root" }; } else { + $scope.loading = true; + mediaResource.getById($scope.relation.parentId).then(function (data) { + $scope.loading = false; $scope.target = data; - // make sure the target item isn't in the recycle bin - if ($scope.target.path.indexOf("-20") !== -1) { - $scope.error = { - errorMsg: localizationService.localize('recycleBin_itemCannotBeRestored'), - data: { - Message: localizationService.localize('recycleBin_restoreUnderRecycled').then(function (value) { - value.replace('%0%', $scope.target.name); - }) - } - }; - $scope.success = false; + // make sure the target item isn't in the recycle bin + if ($scope.target.path.indexOf("-21") !== -1) { + $scope.moving = true; + $scope.target = null; } - }, function (err) { - $scope.success = false; + $scope.loading = false; $scope.error = err; }); } }, function (err) { - $scope.success = false; - $scope.error = err; + $scope.loading = false; + $scope.error = err; }); - $scope.restore = function () { + $scope.restore = function () { + $scope.loading = true; + // this code was copied from `content.move.controller.js` - mediaResource.move({ parentId: $scope.target.id, id: node.id }) + mediaResource.move({ parentId: $scope.target.id, id: $scope.source.id }) .then(function (path) { + $scope.loading = false; $scope.success = true; //first we need to remove the node that launched the dialog @@ -78,7 +149,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController", }); }, function (err) { - $scope.success = false; + $scope.loading = false; $scope.error = err; }); }; diff --git a/src/Umbraco.Web.UI.Client/src/views/media/restore.html b/src/Umbraco.Web.UI.Client/src/views/media/restore.html index 17fff154d1..a24700afe7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/restore.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/restore.html @@ -1,25 +1,96 @@
-
+
+ + -

- Restore {{currentNode.name}} under {{target.name}}? -

+
+
+
{{error.errorMsg}}
+
{{error.data.Message}}
+
+
-
-
{{error.errorMsg}}
-
{{error.data.Message}}
-
+
+
+ {{source.name}} + was restored under + was moved underneath + {{target.name}} +
+ +
-
-

{{currentNode.name}} was moved underneath {{target.name}}

- -
+
+ +

+ Restore {{source.name}} under {{target.name}}? +

+ +
+ +
+
+
+
Cannot automatically restore this item
+
There is no location where this item can be automatically restored. You can move the item manually using the tree below.
+
+
+ +
+ + + +
+ + + + +
+ + +
+
+ + + + +
-
-
Required alias
-
Invalid alias
-
{{lockedFieldForm.lockedField.errorMsg}}
+
+ Required alias +
+
+ Invalid alias +
+
{{lockedFieldForm.lockedField.errorMsg}} +
From adc9957504dce78296f70c86557fc47f69af377c Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 16 Jan 2019 22:27:58 +0100 Subject: [PATCH 177/223] Show the media link in the info app --- .../views/components/media/umb-media-node-info.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html b/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html index 2e09fbfa3b..4004c2b958 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html @@ -5,16 +5,16 @@ -

diff --git a/src/Umbraco.Web.UI.Client/src/views/media/move.html b/src/Umbraco.Web.UI.Client/src/views/media/move.html index 6f80b5ab90..2aebda195c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/move.html @@ -27,7 +27,7 @@

- Date: Thu, 17 Jan 2019 16:37:33 +0100 Subject: [PATCH 184/223] Added processJs --- src/Umbraco.Web.UI.Client/gulp/tasks/watch.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/watch.js b/src/Umbraco.Web.UI.Client/gulp/tasks/watch.js index f9f48b043f..a5c476f7d2 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/watch.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/watch.js @@ -6,6 +6,8 @@ var gulp = require('gulp'); var _ = require('lodash'); var MergeStream = require('merge-stream'); +var processJs = require('../util/processJs'); + var watch = require('gulp-watch'); gulp.task('watch', function () { From 89a2c1b32dcba71e222826bdac227f521494f5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 17 Jan 2019 17:02:12 +0100 Subject: [PATCH 185/223] Fix merge of pull request #4120 --- src/Umbraco.Web.UI.Client/gulpfile.js | 601 +------------------------- 1 file changed, 14 insertions(+), 587 deletions(-) mode change 100644 => 100755 src/Umbraco.Web.UI.Client/gulpfile.js diff --git a/src/Umbraco.Web.UI.Client/gulpfile.js b/src/Umbraco.Web.UI.Client/gulpfile.js old mode 100644 new mode 100755 index 0e94fad5d2..f01d992013 --- a/src/Umbraco.Web.UI.Client/gulpfile.js +++ b/src/Umbraco.Web.UI.Client/gulpfile.js @@ -1,587 +1,14 @@ -var gulp = require('gulp'); -var watch = require('gulp-watch'); -var concat = require('gulp-concat'); -var rename = require('gulp-rename'); -var wrap = require("gulp-wrap-js"); -var sort = require('gulp-sort'); -var connect = require('gulp-connect'); -var open = require('gulp-open'); -var babel = require("gulp-babel"); -var runSequence = require('run-sequence'); -var imagemin = require('gulp-imagemin'); - -var _ = require('lodash'); -var MergeStream = require('merge-stream'); - -// js -var eslint = require('gulp-eslint'); - -//Less + css -var postcss = require('gulp-postcss'); -var less = require('gulp-less'); -var autoprefixer = require('autoprefixer'); -var cssnano = require('cssnano'); -var cleanCss = require("gulp-clean-css"); - -// Documentation -var gulpDocs = require('gulp-ngdocs'); - -// Testing -var karmaServer = require('karma').Server; - -/*************************************************************** -Helper functions -***************************************************************/ -function processJs(files, out) { - - return gulp.src(files) - // check for js errors - .pipe(eslint()) - // outputs the lint results to the console - .pipe(eslint.format()) - // sort files in stream by path or any custom sort comparator - .pipe(babel()) - .pipe(sort()) - .pipe(concat(out)) - .pipe(wrap('(function(){\n%= body %\n})();')) - .pipe(gulp.dest(root + targets.js)); - - console.log(out + " compiled"); -} - -function processLess(files, out) { - var processors = [ - autoprefixer, - cssnano({zindex: false}) - ]; - - return gulp.src(files) - .pipe(less()) - .pipe(cleanCss()) - .pipe(postcss(processors)) - .pipe(rename(out)) - .pipe(gulp.dest(root + targets.css)); - - console.log(out + " compiled"); -} - -/*************************************************************** -Paths and destinations -Each group is iterated automatically in the setup tasks below -***************************************************************/ -var sources = { - - //less files used by backoffice and preview - //processed in the less task - less: { - installer: { files: ["src/less/installer.less"], out: "installer.css" }, - nonodes: { files: ["src/less/pages/nonodes.less"], out: "nonodes.style.min.css"}, - preview: { files: ["src/less/canvas-designer.less"], out: "canvasdesigner.css" }, - umbraco: { files: ["src/less/belle.less"], out: "umbraco.css" } - }, - - //js files for backoffie - //processed in the js task - js: { - preview: { files: ["src/preview/**/*.js"], out: "umbraco.preview.js" }, - installer: { files: ["src/installer/**/*.js"], out: "umbraco.installer.js" }, - controllers: { files: ["src/{views,controllers}/**/*.controller.js"], out: "umbraco.controllers.js" }, - directives: { files: ["src/common/directives/**/*.js"], out: "umbraco.directives.js" }, - filters: { files: ["src/common/filters/**/*.js"], out: "umbraco.filters.js" }, - resources: { files: ["src/common/resources/**/*.js"], out: "umbraco.resources.js" }, - services: { files: ["src/common/services/**/*.js"], out: "umbraco.services.js" }, - security: { files: ["src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" } - }, - - //selectors for copying all views into the build - //processed in the views task - views:{ - umbraco: {files: ["src/views/**/*.html"], folder: ""}, - installer: {files: ["src/installer/steps/*.html"], folder: "install"} - }, - - //globs for file-watching - globs:{ - views: "./src/views/**/*.html", - less: "./src/less/**/*.less", - js: "./src/*.js", - lib: "./lib/**/*", - assets: "./src/assets/**" - } -}; - -var root = "../Umbraco.Web.UI/Umbraco/"; -var targets = { - js: "js/", - lib: "lib/", - views: "views/", - css: "assets/css/", - assets: "assets/" -}; - - -/************************** - * Main tasks for the project to prepare backoffice files - **************************/ - - // Build - build the files ready for production -gulp.task('build', function(cb) { - runSequence(["dependencies", "js", "less", "views"], cb); -}); - -// Dev - build the files ready for development and start watchers -gulp.task('dev', function(cb) { - runSequence(["dependencies", "js", "less", "views"], "watch", cb); -}); - -// Docserve - build and open the back office documentation -gulp.task('docserve', function(cb) { - runSequence('docs', 'connect:docs', 'open:docs', cb); -}); - -/************************** - * Task processes and copies all dependencies, either installed by npm or stored locally in the project - **************************/ -gulp.task('dependencies', function () { - - //as we do multiple things in this task, we merge the multiple streams - var stream = new MergeStream(); - - // Pick the dependencies we need from each package - // so we don't just ship with a lot of files that aren't needed - const nodeModules = [ - { - "name": "ace-builds", - "src": [ - "./node_modules/ace-builds/src-min-noconflict/ace.js", - "./node_modules/ace-builds/src-min-noconflict/ext-language_tools.js", - "./node_modules/ace-builds/src-min-noconflict/ext-searchbox.js", - "./node_modules/ace-builds/src-min-noconflict/ext-settings_menu.js", - "./node_modules/ace-builds/src-min-noconflict/snippets/text.js", - "./node_modules/ace-builds/src-min-noconflict/snippets/javascript.js", - "./node_modules/ace-builds/src-min-noconflict/snippets/css.js", - "./node_modules/ace-builds/src-min-noconflict/theme-chrome.js", - "./node_modules/ace-builds/src-min-noconflict/mode-razor.js", - "./node_modules/ace-builds/src-min-noconflict/mode-javascript.js", - "./node_modules/ace-builds/src-min-noconflict/mode-css.js", - "./node_modules/ace-builds/src-min-noconflict/worker-javascript.js", - "./node_modules/ace-builds/src-min-noconflict/worker-css.js" - ], - "base": "./node_modules/ace-builds" - }, - { - "name": "angular", - "src": ["./node_modules/angular/angular.js"], - "base": "./node_modules/angular" - }, - { - "name": "angular-cookies", - "src": ["./node_modules/angular-cookies/angular-cookies.js"], - "base": "./node_modules/angular-cookies" - }, - { - "name": "angular-dynamic-locale", - "src": [ - "./node_modules/angular-dynamic-locale/dist/tmhDynamicLocale.min.js", - "./node_modules/angular-dynamic-locale/dist/tmhDynamicLocale.min.js.map" - ], - "base": "./node_modules/angular-dynamic-locale/dist" - }, - { - "name": "angular-sanitize", - "src": ["./node_modules/angular-sanitize/angular-sanitize.js"], - "base": "./node_modules/angular-sanitize" - }, - { - "name": "angular-touch", - "src": ["./node_modules/angular-touch/angular-touch.js"], - "base": "./node_modules/angular-touch" - }, - { - "name": "angular-ui-sortable", - "src": ["./node_modules/angular-ui-sortable/dist/sortable.js"], - "base": "./node_modules/angular-ui-sortable/dist" - }, - { - "name": "angular-route", - "src": ["./node_modules/angular-route/angular-route.js"], - "base": "./node_modules/angular-route" - }, - { - "name": "angular-animate", - "src": ["./node_modules/angular-animate/angular-animate.js"], - "base": "./node_modules/angular-animate" - }, - { - "name": "angular-i18n", - "src": [ - "./node_modules/angular-i18n/angular-i18n.js", - "./node_modules/angular-i18n/angular-locale_*.js" - ], - "base": "./node_modules/angular-i18n" - }, - { - "name": "angular-local-storage", - "src": [ - "./node_modules/angular-local-storage/dist/angular-local-storage.min.js", - "./node_modules/angular-local-storage/dist/angular-local-storage.min.js.map" - ], - "base": "./node_modules/angular-local-storage/dist" - }, - { - "name": "angular-messages", - "src": ["./node_modules/angular-messages/angular-messages.js"], - "base": "./node_modules/angular-messages" - }, - { - "name": "angular-mocks", - "src": ["./node_modules/angular-mocks/angular-mocks.js"], - "base": "./node_modules/angular-mocks" - }, - { - "name": "animejs", - "src": ["./node_modules/animejs/anime.min.js"], - "base": "./node_modules/animejs" - }, - { - "name": "bootstrap-social", - "src": ["./node_modules/bootstrap-social/bootstrap-social.css"], - "base": "./node_modules/bootstrap-social" - }, - - { - "name": "angular-chart.js", - "src": ["./node_modules/angular-chart.js/dist/angular-chart.min.js"], - "base": "./node_modules/angular-chart.js/dist" - }, - { - "name": "chart.js", - "src": ["./node_modules/chart.js/dist/chart.min.js"], - "base": "./node_modules/chart.js/dist" - }, - { - "name": "clipboard", - "src": ["./node_modules/clipboard/dist/clipboard.min.js"], - "base": "./node_modules/clipboard/dist" - }, - { - "name": "jsdiff", - "src": ["./node_modules/diff/dist/diff.min.js"], - "base": "./node_modules/diff/dist" - }, - { - "name": "flatpickr", - "src": [ - "./node_modules/flatpickr/dist/flatpickr.js", - "./node_modules/flatpickr/dist/flatpickr.css" - ], - "base": "./node_modules/flatpickr/dist" - }, - { - "name": "font-awesome", - "src": [ - "./node_modules/font-awesome/fonts/*", - "./node_modules/font-awesome/css/font-awesome.min.css" - ], - "base": "./node_modules/font-awesome" - }, - { - "name": "jquery", - "src": [ - "./node_modules/jquery/dist/jquery.min.js", - "./node_modules/jquery/dist/jquery.min.map" - ], - "base": "./node_modules/jquery/dist" - }, - { - "name": "jquery-ui", - "src": ["./node_modules/jquery-ui-dist/jquery-ui.min.js"], - "base": "./node_modules/jquery-ui-dist" - }, - { - "name": "jquery-ui-touch-punch", - "src": ["./node_modules/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js"], - "base": "./node_modules/jquery-ui-touch-punch" - }, - { - "name": "lazyload-js", - "src": ["./node_modules/lazyload-js/lazyload.min.js"], - "base": "./node_modules/lazyload-js" - }, - { - "name": "moment", - "src": ["./node_modules/moment/min/moment.min.js"], - "base": "./node_modules/moment/min" - }, - { - "name": "moment", - "src": ["./node_modules/moment/locale/*.js"], - "base": "./node_modules/moment/locale" - }, - { - "name": "ng-file-upload", - "src": ["./node_modules/ng-file-upload/dist/ng-file-upload.min.js"], - "base": "./node_modules/ng-file-upload/dist" - }, - { - "name": "nouislider", - "src": [ - "./node_modules/nouislider/distribute/nouislider.min.js", - "./node_modules/nouislider/distribute/nouislider.min.css" - ], - "base": "./node_modules/nouislider/distribute" - }, - { - "name": "signalr", - "src": ["./node_modules/signalr/jquery.signalR.js"], - "base": "./node_modules/signalr" - }, - { - "name": "spectrum", - "src": [ - "./node_modules/spectrum-colorpicker/spectrum.js", - "./node_modules/spectrum-colorpicker/spectrum.css" - ], - "base": "./node_modules/spectrum-colorpicker" - }, - { - "name": "tinymce", - "src": [ - "./node_modules/tinymce/tinymce.min.js", - "./node_modules/tinymce/plugins/**", - "./node_modules/tinymce/skins/**", - "./node_modules/tinymce/themes/**" - ], - "base": "./node_modules/tinymce" - }, - { - "name": "typeahead.js", - "src": ["./node_modules/typeahead.js/dist/typeahead.bundle.min.js"], - "base": "./node_modules/typeahead.js/dist" - }, - { - "name": "underscore", - "src": ["node_modules/underscore/underscore-min.js"], - "base": "./node_modules/underscore" - } - ]; - - // add streams for node modules - nodeModules.forEach(module => { - stream.add( - gulp.src(module.src, - { base: module.base }) - .pipe(gulp.dest(root + targets.lib + "/" + module.name)) - ); - }); - - //copy over libs which are not on npm (/lib) - stream.add( - gulp.src(sources.globs.lib) - .pipe(gulp.dest(root + targets.lib)) - ); - - //Copies all static assets into /root / assets folder - //css, fonts and image files - stream.add( - gulp.src(sources.globs.assets) - .pipe(imagemin([ - imagemin.gifsicle({interlaced: true}), - imagemin.jpegtran({progressive: true}), - imagemin.optipng({optimizationLevel: 5}), - imagemin.svgo({ - plugins: [ - {removeViewBox: true}, - {cleanupIDs: false} - ] - }) - ])) - .pipe(gulp.dest(root + targets.assets)) - ); - - // Copies all the less files related to the preview into their folder - //these are not pre-processed as preview has its own less combiler client side - stream.add( - gulp.src("src/canvasdesigner/editors/*.less") - .pipe(gulp.dest(root + targets.assets + "/less")) - ); - - // Todo: check if we need these fileSize - stream.add( - gulp.src("src/views/propertyeditors/grid/config/*.*") - .pipe(gulp.dest(root + targets.views + "/propertyeditors/grid/config")) - ); - stream.add( - gulp.src("src/views/dashboard/default/*.jpg") - .pipe(gulp.dest(root + targets.views + "/dashboard/default")) - ); - - return stream; -}); - - -/************************** - * Copies all angular JS files into their separate umbraco.*.js file - **************************/ -gulp.task('js', function () { - - //we run multiple streams, so merge them all together - var stream = new MergeStream(); - - stream.add( - gulp.src(sources.globs.js) - .pipe(gulp.dest(root + targets.js)) - ); - - _.forEach(sources.js, function (group) { - stream.add (processJs(group.files, group.out) ); - }); - - return stream; -}); - -gulp.task('less', function () { - - var stream = new MergeStream(); - - _.forEach(sources.less, function (group) { - stream.add( processLess(group.files, group.out) ); - }); - - return stream; -}); - - -gulp.task('views', function () { - - var stream = new MergeStream(); - - _.forEach(sources.views, function (group) { - - console.log("copying " + group.files + " to " + root + targets.views + group.folder) - - stream.add ( - gulp.src(group.files) - .pipe( gulp.dest(root + targets.views + group.folder) ) - ); - - }); - - return stream; -}); - - -gulp.task('watch', function () { - - var stream = new MergeStream(); - var watchInterval = 500; - - //Setup a watcher for all groups of javascript files - _.forEach(sources.js, function (group) { - - if(group.watch !== false){ - - stream.add( - - watch(group.files, { ignoreInitial: true, interval: watchInterval }, function (file) { - - console.info(file.path + " has changed, added to: " + group.out); - processJs(group.files, group.out); - - }) - - ); - - } - - }); - - stream.add( - //watch all less files and trigger the less task - watch(sources.globs.less, { ignoreInitial: true, interval: watchInterval }, function () { - gulp.run(['less']); - }) - ); - - //watch all views - copy single file changes - stream.add( - watch(sources.globs.views, { interval: watchInterval }) - .pipe(gulp.dest(root + targets.views)) - ); - - //watch all app js files that will not be merged - copy single file changes - stream.add( - watch(sources.globs.js, { interval: watchInterval }) - .pipe(gulp.dest(root + targets.js)) - ); - - return stream; -}); - -/************************** - * Build Backoffice UI API documentation - **************************/ -gulp.task('docs', [], function (cb) { - - var options = { - html5Mode: false, - startPage: '/api', - title: "Umbraco Backoffice UI API Documentation", - dest: 'docs/api', - styles: ['docs/umb-docs.css'], - image: "https://our.umbraco.com/assets/images/logo.svg" - } - - return gulpDocs.sections({ - api: { - glob: ['src/common/**/*.js', 'docs/src/api/**/*.ngdoc'], - api: true, - title: 'API Documentation' - } - }) - .pipe(gulpDocs.process(options)) - .pipe(gulp.dest('docs/api')); - cb(); -}); - -gulp.task('connect:docs', function (cb) { - connect.server({ - root: 'docs/api', - livereload: true, - fallback: 'docs/api/index.html', - port: 8880 - }); - cb(); -}); - -gulp.task('open:docs', function (cb) { - - var options = { - uri: 'http://localhost:8880/index.html' - }; - - gulp.src(__filename) - .pipe(open(options)); - cb(); -}); - -/************************** - * Build tests - **************************/ - - // Karma test -gulp.task('test:unit', function() { - new karmaServer({ - configFile: __dirname + "/test/config/karma.conf.js", - keepalive: true - }) - .start(); -}); - -gulp.task('test:e2e', function() { - new karmaServer({ - configFile: __dirname + "/test/config/e2e.js", - keepalive: true - }) - .start(); -}); +'use strict'; + +/* + * gulpfile.js + * =========== + * Rather than manage one giant configuration file responsible + * for creating multiple tasks, each task has been broken out into + * its own file in gulp/tasks. Any file in that folder gets automatically + * required by the loop in ./gulp/index.js (required below). + * + * To add a new task, simply add a new task file to gulp/tasks. + */ + +require('./gulp'); From 42f32e61e95c0695b39d2c0e2e08995be1ff3f0c Mon Sep 17 00:00:00 2001 From: mclausen Date: Thu, 17 Jan 2019 17:15:22 +0100 Subject: [PATCH 186/223] - Added PropertyType to The IValueConnector --- src/Umbraco.Core/Deploy/IValueConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Deploy/IValueConnector.cs b/src/Umbraco.Core/Deploy/IValueConnector.cs index 92589ab6cf..81df59f1f1 100644 --- a/src/Umbraco.Core/Deploy/IValueConnector.cs +++ b/src/Umbraco.Core/Deploy/IValueConnector.cs @@ -20,9 +20,10 @@ namespace Umbraco.Core.Deploy /// Gets the deploy property value corresponding to a content property value, and gather dependencies. ///
/// The content property value. + /// The value property type /// The content dependencies. /// The deploy property value. - string ToArtifact(object value, ICollection dependencies); + string ToArtifact(object value, PropertyType propertyType, ICollection dependencies); /// /// Gets the content property value corresponding to a deploy property value. From e42995cf101347d82ac3069ccb293711fde33f57 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 17 Jan 2019 18:03:07 +0100 Subject: [PATCH 187/223] Fixes for the IPublishedContent Linq/Culture PR --- .../PublishedContentDataTableTests.cs | 74 ++++----- .../PublishedContent/PublishedContentTests.cs | 156 +++++++++--------- .../Accessors/TestVariationContextAccessor.cs | 6 +- .../DictionaryPublishedContent.cs | 5 +- .../XmlPublishedCache/XmlPublishedContent.cs | 5 +- src/Umbraco.Web/PublishedContentExtensions.cs | 27 ++- 6 files changed, 140 insertions(+), 133 deletions(-) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index fa60b050cc..73f3cd1537 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -73,44 +73,44 @@ namespace Umbraco.Tests.PublishedContent Umbraco.Web.PublishedContentExtensions.GetPropertyAliasesAndNames = null; } -// [Test] -// public void To_DataTable() -// { -// var doc = GetContent(true, 1); -// var dt = doc.ChildrenAsTable(Current.Services); -// -// Assert.AreEqual(11, dt.Columns.Count); -// Assert.AreEqual(3, dt.Rows.Count); -// Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); -// Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); -// Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); -// Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); -// Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); -// Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); -// Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); -// Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); -// Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); -// } + [Test] + public void To_DataTable() + { + var doc = GetContent(true, 1); + var dt = doc.ChildrenAsTable(Current.Services); -// [Test] -// public void To_DataTable_With_Filter() -// { -// var doc = GetContent(true, 1); -// //change a doc type alias -// var c = (TestPublishedContent) doc.Children.ElementAt(0); -// c.ContentType = new PublishedContentType(22, "DontMatch", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); -// -// var dt = doc.ChildrenAsTable(Current.Services, "Child"); -// -// Assert.AreEqual(11, dt.Columns.Count); -// Assert.AreEqual(2, dt.Rows.Count); -// Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); -// Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); -// Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); -// Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); -// Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); -// Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); -// } + Assert.AreEqual(11, dt.Columns.Count); + Assert.AreEqual(3, dt.Rows.Count); + Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); + Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); + Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); + Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); + Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); + Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); + Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); + Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); + Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); + } + + [Test] + public void To_DataTable_With_Filter() + { + var doc = GetContent(true, 1); + //change a doc type alias + var c = (TestPublishedContent)doc.Children.ElementAt(0); + c.ContentType = new PublishedContentType(22, "DontMatch", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); + + var dt = doc.ChildrenAsTable(Current.Services, "Child"); + + Assert.AreEqual(11, dt.Columns.Count); + Assert.AreEqual(2, dt.Rows.Count); + Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); + Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); + Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); + Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); + Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); + Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); + } [Test] public void To_DataTable_No_Rows() diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 855d864cc4..603464e18b 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -326,18 +326,18 @@ namespace Umbraco.Tests.PublishedContent } } -// [Test] -// public void Descendants_Ordered_Properly() -// { -// var doc = GetNode(1046); -// -// var expected = new[] { 1046, 1173, 1174, 117, 1177, 1178, 1179, 1176, 1175, 4444, 1172 }; -// var exindex = 0; -// -// // must respect the XPath descendants-or-self axis! -// foreach (var d in doc.DescendantsOrSelf()) -// Assert.AreEqual(expected[exindex++], d.Id); -// } + [Test] + public void Descendants_Ordered_Properly() + { + var doc = GetNode(1046); + + var expected = new[] { 1046, 1173, 1174, 117, 1177, 1178, 1179, 1176, 1175, 4444, 1172 }; + var exindex = 0; + + // must respect the XPath descendants-or-self axis! + foreach (var d in doc.DescendantsOrSelf()) + Assert.AreEqual(expected[exindex++], d.Id); + } [Test] public void Get_Property_Value_Recursive() @@ -367,18 +367,18 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual("
This is some content
", propVal3.ToString()); } -// [Test] -// public void Complex_Linq() -// { -// var doc = GetNode(1173); -// -// var result = doc.Ancestors().OrderBy(x => x.Level) -// .Single() -// .Descendants() -// .FirstOrDefault(x => x.Value("selectedNodes", defaultValue: "").Split(',').Contains("1173")); -// -// Assert.IsNotNull(result); -// } + [Test] + public void Complex_Linq() + { + var doc = GetNode(1173); + + var result = doc.Ancestors().OrderBy(x => x.Level) + .Single() + .Descendants() + .FirstOrDefault(x => x.Value("selectedNodes", defaultValue: "").Split(',').Contains("1173")); + + Assert.IsNotNull(result); + } [Test] public void Children_GroupBy_DocumentTypeAlias() @@ -437,36 +437,36 @@ namespace Umbraco.Tests.PublishedContent } -// [Test] -// public void FirstChild() -// { -// var doc = GetNode(1173); // has child nodes -// Assert.IsNotNull(doc.FirstChild()); -// Assert.IsNotNull(doc.FirstChild(x => true)); -// Assert.IsNotNull(doc.FirstChild()); -// -// doc = GetNode(1175); // does not have child nodes -// Assert.IsNull(doc.FirstChild()); -// Assert.IsNull(doc.FirstChild(x => true)); -// Assert.IsNull(doc.FirstChild()); -// } + [Test] + public void FirstChild() + { + var doc = GetNode(1173); // has child nodes + Assert.IsNotNull(doc.FirstChild()); + Assert.IsNotNull(doc.FirstChild(x => true)); + Assert.IsNotNull(doc.FirstChild()); -// [Test] -// public void FirstChildAsT() -// { -// var doc = GetNode(1046); // has child nodes -// -// var model = doc.FirstChild(x => true); // predicate -// -// Assert.IsNotNull(model); -// Assert.IsTrue(model.Id == 1173); -// Assert.IsInstanceOf(model); -// Assert.IsInstanceOf(model); -// -// doc = GetNode(1175); // does not have child nodes -// Assert.IsNull(doc.FirstChild()); -// Assert.IsNull(doc.FirstChild(x => true)); -// } + doc = GetNode(1175); // does not have child nodes + Assert.IsNull(doc.FirstChild()); + Assert.IsNull(doc.FirstChild(x => true)); + Assert.IsNull(doc.FirstChild()); + } + + [Test] + public void FirstChildAsT() + { + var doc = GetNode(1046); // has child nodes + + var model = doc.FirstChild(x => true); // predicate + + Assert.IsNotNull(model); + Assert.IsTrue(model.Id == 1173); + Assert.IsInstanceOf(model); + Assert.IsInstanceOf(model); + + doc = GetNode(1175); // does not have child nodes + Assert.IsNull(doc.FirstChild()); + Assert.IsNull(doc.FirstChild(x => true)); + } [Test] public void IsComposedOf() @@ -668,31 +668,31 @@ namespace Umbraco.Tests.PublishedContent } -// [Test] -// public void Descendants_Or_Self() -// { -// var doc = GetNode(1046); -// -// var result = doc.DescendantsOrSelf().ToArray(); -// -// Assert.IsNotNull(result); -// -// Assert.AreEqual(10, result.Count()); -// Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 })); -// } -// -// [Test] -// public void Descendants() -// { -// var doc = GetNode(1046); -// -// var result = doc.Descendants().ToArray(); -// -// Assert.IsNotNull(result); -// -// Assert.AreEqual(9, result.Count()); -// Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); -// } + [Test] + public void Descendants_Or_Self() + { + var doc = GetNode(1046); + + var result = doc.DescendantsOrSelf().ToArray(); + + Assert.IsNotNull(result); + + Assert.AreEqual(10, result.Count()); + Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 })); + } + + [Test] + public void Descendants() + { + var doc = GetNode(1046); + + var result = doc.Descendants().ToArray(); + + Assert.IsNotNull(result); + + Assert.AreEqual(9, result.Count()); + Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); + } [Test] public void IsDescendant() diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs b/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs index 4b56799fa4..134b709447 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs +++ b/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs @@ -8,10 +8,6 @@ namespace Umbraco.Tests.Testing.Objects.Accessors public class TestVariationContextAccessor : IVariationContextAccessor { /// - public VariationContext VariationContext - { - get; - set; - } = new VariationContext(); + public VariationContext VariationContext { get; set; } } } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index 6f6a39144a..c418b7a525 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -154,9 +154,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public override string Name => _name; - public override PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException(); + public override PublishedCultureInfo GetCulture(string culture = null) => null; - public override IReadOnlyDictionary Cultures => throw new NotSupportedException(); + private static readonly Lazy> NoCultures = new Lazy>(() => new Dictionary()); + public override IReadOnlyDictionary Cultures => NoCultures.Value; public override string UrlSegment => _urlName; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index d8436c05b5..65c7dc7229 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -136,9 +136,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache } } - public override PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException(); + public override PublishedCultureInfo GetCulture(string culture = null) => null; - public override IReadOnlyDictionary Cultures => new Dictionary(); + private static readonly Lazy> NoCultures = new Lazy>(() => new Dictionary()); + public override IReadOnlyDictionary Cultures => NoCultures.Value; public override string WriterName { diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 4efe6bc82b..0ada3d8c5b 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -267,19 +267,20 @@ namespace Umbraco.Web => content.Cultures.ContainsKey(culture); /// - /// Filter by the specific culture or invariant. If null is provided, the method uses the current culture instead. + /// Filters a sequence of to return invariant items, and items that are published for the specified culture. /// - /// The content. - /// The specific culture to filter for. If null is used the current culture is used. (Default is null) - /// These of the inputs that has the specified culture or are invariant. - internal static IEnumerable WhereHasCultureOrInvariant(this IEnumerable contents, string culture = null) + /// The content items. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null). + internal static IEnumerable WhereIsInvariantOrHasCulture(this IEnumerable contents, string culture = null) { if (contents == null) throw new ArgumentNullException(nameof(contents)); - var actualCulture = culture ?? Current.VariationContextAccessor.VariationContext.Culture; + culture = culture ?? Current.VariationContextAccessor.VariationContext?.Culture ?? ""; - return contents.Where(x=>x.HasCulture(actualCulture) || !x.Cultures.Any()); + // either does not vary by culture, or has the specified culture + return contents.Where(x => !x.ContentType.VariesByCulture() || x.HasCulture(culture)); } + #endregion #region Search @@ -1036,7 +1037,6 @@ namespace Umbraco.Web #region Axes: children - /// /// Gets the children of the content. /// @@ -1050,7 +1050,16 @@ namespace Umbraco.Web public static IEnumerable Children(this IPublishedContent content, string culture = null) { if (content == null) throw new ArgumentNullException(nameof(content)); - return content.Children.WhereHasCultureOrInvariant(culture); + + // + return content.Children.Where(x => + { + if (!x.ContentType.VariesByCulture()) return true; // invariant = always ok + return x.HasCulture(culture); + return false; + }); + + return content.Children.WhereIsInvariantOrHasCulture(culture); } /// From 537b7e5ce9845f64a42dfc57479140ab1b0c438c Mon Sep 17 00:00:00 2001 From: mclausen Date: Thu, 17 Jan 2019 18:52:08 +0100 Subject: [PATCH 188/223] - Added PropertyType parameter to IValueConnector.FromArtifact --- src/Umbraco.Core/Deploy/IValueConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Deploy/IValueConnector.cs b/src/Umbraco.Core/Deploy/IValueConnector.cs index 81df59f1f1..7d9f43b5fe 100644 --- a/src/Umbraco.Core/Deploy/IValueConnector.cs +++ b/src/Umbraco.Core/Deploy/IValueConnector.cs @@ -29,8 +29,9 @@ namespace Umbraco.Core.Deploy /// Gets the content property value corresponding to a deploy property value. /// /// The deploy property value. + /// The value property type< /// The current content property value. /// The content property value. - object FromArtifact(string value, object currentValue); + object FromArtifact(string value, PropertyType propertyType, object currentValue); } } From 1ceab77aefebbb005257bbaa94c47e127a187335 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 16 Jan 2019 08:48:47 +0100 Subject: [PATCH 189/223] Fix start node configuration for tree pickers --- src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs | 4 ++-- src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs | 4 ++-- .../PropertyEditors/MultiNodePickerConfigurationTreeSource.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs index fe6ab6a054..307e41b836 100644 --- a/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs @@ -8,6 +8,6 @@ namespace Umbraco.Web.PropertyEditors public bool ShowOpenButton { get; set; } [ConfigurationField("startNodeId", "Start node", "treepicker")] // + config in configuration editor ctor - public int StartNodeId { get; set; } = -1; // default value is -1 + public string StartNodeId { get; set; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs index 382db7e414..633fd65598 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs @@ -17,6 +17,6 @@ namespace Umbraco.Web.PropertyEditors public bool DisableFolderSelect { get; set; } [ConfigurationField("startNodeId", "Start node", "mediapicker")] - public int StartNodeId { get; set; } + public string StartNodeId { get; set; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs index ffedf6c7dc..65115afc63 100644 --- a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs +++ b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs @@ -15,6 +15,6 @@ namespace Umbraco.Web.PropertyEditors public string StartNodeQuery {get;set;} [JsonProperty("id")] - public int? StartNodeId {get;set;} + public string StartNodeId {get;set;} } } From f394bed017f2a5079f815ae11b4bf33d75bbfaea Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 17 Jan 2019 19:31:35 +0100 Subject: [PATCH 190/223] Change StartNodeId from string to Udi --- .../PropertyEditors/ContentPickerConfiguration.cs | 5 +++-- src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs | 5 +++-- .../MultiNodePickerConfigurationTreeSource.cs | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs index 307e41b836..7879e2b42b 100644 --- a/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.PropertyEditors; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { @@ -8,6 +9,6 @@ namespace Umbraco.Web.PropertyEditors public bool ShowOpenButton { get; set; } [ConfigurationField("startNodeId", "Start node", "treepicker")] // + config in configuration editor ctor - public string StartNodeId { get; set; } + public Udi StartNodeId { get; set; } } } diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs index 633fd65598..4844e2f822 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.PropertyEditors; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { @@ -17,6 +18,6 @@ namespace Umbraco.Web.PropertyEditors public bool DisableFolderSelect { get; set; } [ConfigurationField("startNodeId", "Start node", "mediapicker")] - public string StartNodeId { get; set; } + public Udi StartNodeId { get; set; } } } diff --git a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs index 65115afc63..2942271acc 100644 --- a/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs +++ b/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using Umbraco.Core; namespace Umbraco.Web.PropertyEditors { @@ -15,6 +16,6 @@ namespace Umbraco.Web.PropertyEditors public string StartNodeQuery {get;set;} [JsonProperty("id")] - public string StartNodeId {get;set;} + public Udi StartNodeId {get;set;} } } From 27a1e51f80f38e24a29de02105128f5e7126549f Mon Sep 17 00:00:00 2001 From: Kenneth Jakobsen Date: Thu, 17 Jan 2019 21:12:10 +0100 Subject: [PATCH 191/223] Removed Property parameter from IGridCellValueVConnector --- src/Umbraco.Core/Deploy/IGridCellValueConnector.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs b/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs index 827a902b89..5492a3effe 100644 --- a/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs +++ b/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs @@ -22,20 +22,17 @@ namespace Umbraco.Core.Deploy /// Gets the value to be deployed from the control value as a string. ///
/// The control containing the value. - /// The property where the control is located. Do not modify - only used for context /// The dependencies of the property. /// The grid cell value to be deployed. /// Note that - string GetValue(GridValue.GridControl gridControl, Property property, ICollection dependencies); + string ToArtifact(GridValue.GridControl gridControl, ICollection dependencies); /// /// Allows you to modify the value of a control being deployed. /// /// The control being deployed. - /// The property where the is located. Do not modify - only used for context. /// Follows the pattern of the property value connectors (). The SetValue method is used to modify the value of the . - /// Note that only the value should be modified - not the . - /// The should only be used to assist with context data relevant when setting the value. - void SetValue(GridValue.GridControl gridControl, Property property); + + void FromArtifact(GridValue.GridControl gridControl); } } From 9fed610902f99a51d97f8447d5b4c4296f8e33f6 Mon Sep 17 00:00:00 2001 From: Kenneth Jakobsen Date: Thu, 17 Jan 2019 21:32:08 +0100 Subject: [PATCH 192/223] Redecided on renaming --- src/Umbraco.Core/Deploy/IGridCellValueConnector.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs b/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs index 5492a3effe..15ed404d31 100644 --- a/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs +++ b/src/Umbraco.Core/Deploy/IGridCellValueConnector.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Deploy /// The dependencies of the property. /// The grid cell value to be deployed. /// Note that - string ToArtifact(GridValue.GridControl gridControl, ICollection dependencies); + string GetValue(GridValue.GridControl gridControl, ICollection dependencies); /// /// Allows you to modify the value of a control being deployed. @@ -33,6 +33,6 @@ namespace Umbraco.Core.Deploy /// The control being deployed. /// Follows the pattern of the property value connectors (). The SetValue method is used to modify the value of the . - void FromArtifact(GridValue.GridControl gridControl); + void SetValue(GridValue.GridControl gridControl); } } From 5aba1a6bd29c25101485f0b10e8321a3d2f81855 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 18 Jan 2019 07:56:38 +0100 Subject: [PATCH 193/223] IAppPolicedCache is IAppPolicyCache --- src/Umbraco.Core/Cache/AppCaches.cs | 4 ++-- .../Cache/AppPolicedCacheDictionary.cs | 14 +++++++------- src/Umbraco.Core/Cache/CacheProviderExtensions.cs | 4 ++-- src/Umbraco.Core/Cache/DeepCloneAppCache.cs | 8 ++++---- .../Cache/DefaultRepositoryCachePolicy.cs | 2 +- .../Cache/FullDataSetRepositoryCachePolicy.cs | 2 +- .../{IAppPolicedCache.cs => IAppPolicyCache.cs} | 2 +- src/Umbraco.Core/Cache/IsolatedCaches.cs | 8 ++++---- src/Umbraco.Core/Cache/NoAppCache.cs | 4 ++-- .../Cache/NoCacheRepositoryCachePolicy.cs | 2 +- src/Umbraco.Core/Cache/ObjectCacheAppCache.cs | 4 ++-- .../Cache/RepositoryCachePolicyBase.cs | 6 +++--- .../Cache/SingleItemsOnlyRepositoryCachePolicy.cs | 2 +- src/Umbraco.Core/Cache/WebCachingAppCache.cs | 4 ++-- src/Umbraco.Core/Composing/TypeLoader.cs | 6 +++--- src/Umbraco.Core/Manifest/ManifestParser.cs | 2 +- .../Implement/RepositoryBaseOfTIdTEntity.cs | 6 +++--- .../Implement/LocalizedTextServiceFileSources.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- .../Cache/DeepCloneRuntimeCacheProviderTests.cs | 2 +- src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs | 12 ++++++------ .../Cache/FullDataSetCachePolicyTests.cs | 14 +++++++------- .../Cache/HttpRuntimeCacheProviderTests.cs | 2 +- .../Cache/ObjectCacheProviderTests.cs | 2 +- .../Cache/RuntimeCacheProviderTests.cs | 2 +- .../Cache/SingleItemsOnlyCachePolicyTests.cs | 4 ++-- .../PublishedContentSnapshotTestBase.cs | 2 +- .../PublishedContent/PublishedContentTests.cs | 2 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 6 +++--- .../Editors/ExamineManagementController.cs | 2 +- 30 files changed, 67 insertions(+), 67 deletions(-) rename src/Umbraco.Core/Cache/{IAppPolicedCache.cs => IAppPolicyCache.cs} (97%) diff --git a/src/Umbraco.Core/Cache/AppCaches.cs b/src/Umbraco.Core/Cache/AppCaches.cs index 6372bccbab..7e5fa43682 100644 --- a/src/Umbraco.Core/Cache/AppCaches.cs +++ b/src/Umbraco.Core/Cache/AppCaches.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Cache /// Initializes a new instance of the with cache providers. /// public AppCaches( - IAppPolicedCache runtimeCache, + IAppPolicyCache runtimeCache, IAppCache staticCacheProvider, IAppCache requestCache, IsolatedCaches isolatedCaches) @@ -82,7 +82,7 @@ namespace Umbraco.Core.Cache /// /// The runtime cache is the main application cache. /// - public IAppPolicedCache RuntimeCache { get; } + public IAppPolicyCache RuntimeCache { get; } /// /// Gets the isolated caches. diff --git a/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs b/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs index 51cc3c4c53..5c60dededa 100644 --- a/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs +++ b/src/Umbraco.Core/Cache/AppPolicedCacheDictionary.cs @@ -4,18 +4,18 @@ using System.Collections.Concurrent; namespace Umbraco.Core.Cache { /// - /// Provides a base class for implementing a dictionary of . + /// Provides a base class for implementing a dictionary of . /// /// The type of the dictionary key. public abstract class AppPolicedCacheDictionary { - private readonly ConcurrentDictionary _caches = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _caches = new ConcurrentDictionary(); /// /// Initializes a new instance of the class. /// /// - protected AppPolicedCacheDictionary(Func cacheFactory) + protected AppPolicedCacheDictionary(Func cacheFactory) { CacheFactory = cacheFactory; } @@ -23,19 +23,19 @@ namespace Umbraco.Core.Cache /// /// Gets the internal cache factory, for tests only! /// - internal readonly Func CacheFactory; + internal readonly Func CacheFactory; /// /// Gets or creates a cache. /// - public IAppPolicedCache GetOrCreate(TKey key) + public IAppPolicyCache GetOrCreate(TKey key) => _caches.GetOrAdd(key, k => CacheFactory(k)); /// /// Tries to get a cache. /// - public Attempt Get(TKey key) - => _caches.TryGetValue(key, out var cache) ? Attempt.Succeed(cache) : Attempt.Fail(); + public Attempt Get(TKey key) + => _caches.TryGetValue(key, out var cache) ? Attempt.Succeed(cache) : Attempt.Fail(); /// /// Removes a cache. diff --git a/src/Umbraco.Core/Cache/CacheProviderExtensions.cs b/src/Umbraco.Core/Cache/CacheProviderExtensions.cs index 0e41b981fb..d943d19edb 100644 --- a/src/Umbraco.Core/Cache/CacheProviderExtensions.cs +++ b/src/Umbraco.Core/Cache/CacheProviderExtensions.cs @@ -10,7 +10,7 @@ namespace Umbraco.Core.Cache /// public static class CacheProviderExtensions { - public static T GetCacheItem(this IAppPolicedCache provider, + public static T GetCacheItem(this IAppPolicyCache provider, string cacheKey, Func getCacheItem, TimeSpan? timeout, @@ -23,7 +23,7 @@ namespace Umbraco.Core.Cache return result == null ? default(T) : result.TryConvertTo().Result; } - public static void InsertCacheItem(this IAppPolicedCache provider, + public static void InsertCacheItem(this IAppPolicyCache provider, string cacheKey, Func getCacheItem, TimeSpan? timeout = null, diff --git a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs index cdc66f1db7..eff06e2aad 100644 --- a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs +++ b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs @@ -8,16 +8,16 @@ using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Cache { /// - /// Implements by wrapping an inner other + /// Implements by wrapping an inner other /// instance, and ensuring that all inserts and returns are deep cloned copies of the cache item, /// when the item is deep-cloneable. /// - internal class DeepCloneAppCache : IAppPolicedCache + internal class DeepCloneAppCache : IAppPolicyCache { /// /// Initializes a new instance of the class. /// - public DeepCloneAppCache(IAppPolicedCache innerCache) + public DeepCloneAppCache(IAppPolicyCache innerCache) { var type = typeof (DeepCloneAppCache); @@ -30,7 +30,7 @@ namespace Umbraco.Core.Cache /// /// Gets the inner cache. /// - public IAppPolicedCache InnerCache { get; } + public IAppPolicyCache InnerCache { get; } /// public object Get(string key) diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs index 6f160cd552..c11309c827 100644 --- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Cache private static readonly TEntity[] EmptyEntities = new TEntity[0]; // const private readonly RepositoryCachePolicyOptions _options; - public DefaultRepositoryCachePolicy(IAppPolicedCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) + public DefaultRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) : base(cache, scopeAccessor) { _options = options ?? throw new ArgumentNullException(nameof(options)); diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs index 3bc4c9d059..c3b69d9a6d 100644 --- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core.Cache private readonly Func _entityGetId; private readonly bool _expires; - public FullDataSetRepositoryCachePolicy(IAppPolicedCache cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires) + public FullDataSetRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires) : base(cache, scopeAccessor) { _entityGetId = entityGetId; diff --git a/src/Umbraco.Core/Cache/IAppPolicedCache.cs b/src/Umbraco.Core/Cache/IAppPolicyCache.cs similarity index 97% rename from src/Umbraco.Core/Cache/IAppPolicedCache.cs rename to src/Umbraco.Core/Cache/IAppPolicyCache.cs index 0aee7584df..90b0ccb9fd 100644 --- a/src/Umbraco.Core/Cache/IAppPolicedCache.cs +++ b/src/Umbraco.Core/Cache/IAppPolicyCache.cs @@ -10,7 +10,7 @@ namespace Umbraco.Core.Cache /// /// A cache policy can be used to cache with timeouts, /// or depending on files, and with a remove callback, etc. - public interface IAppPolicedCache : IAppCache + public interface IAppPolicyCache : IAppCache { /// /// Gets an item identified by its key. diff --git a/src/Umbraco.Core/Cache/IsolatedCaches.cs b/src/Umbraco.Core/Cache/IsolatedCaches.cs index bc624be20d..f070fe8b55 100644 --- a/src/Umbraco.Core/Cache/IsolatedCaches.cs +++ b/src/Umbraco.Core/Cache/IsolatedCaches.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Cache { /// - /// Represents a dictionary of for types. + /// Represents a dictionary of for types. /// /// /// Isolated caches are used by e.g. repositories, to ensure that each cached entity @@ -16,20 +16,20 @@ namespace Umbraco.Core.Cache /// Initializes a new instance of the class. /// /// - public IsolatedCaches(Func cacheFactory) + public IsolatedCaches(Func cacheFactory) : base(cacheFactory) { } /// /// Gets a cache. /// - public IAppPolicedCache GetOrCreate() + public IAppPolicyCache GetOrCreate() => GetOrCreate(typeof(T)); /// /// Tries to get a cache. /// - public Attempt Get() + public Attempt Get() => Get(typeof(T)); /// diff --git a/src/Umbraco.Core/Cache/NoAppCache.cs b/src/Umbraco.Core/Cache/NoAppCache.cs index 8a7e15cb29..d3359a30ba 100644 --- a/src/Umbraco.Core/Cache/NoAppCache.cs +++ b/src/Umbraco.Core/Cache/NoAppCache.cs @@ -6,9 +6,9 @@ using System.Web.Caching; namespace Umbraco.Core.Cache { /// - /// Implements and do not cache. + /// Implements and do not cache. /// - public class NoAppCache : IAppPolicedCache + public class NoAppCache : IAppPolicyCache { private NoAppCache() { } diff --git a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs index acc67be679..b1a12ec411 100644 --- a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Cache public static NoCacheRepositoryCachePolicy Instance { get; } = new NoCacheRepositoryCachePolicy(); - public IRepositoryCachePolicy Scoped(IAppPolicedCache runtimeCache, IScope scope) + public IRepositoryCachePolicy Scoped(IAppPolicyCache runtimeCache, IScope scope) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs index 954622fc4b..449eb5d643 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs @@ -11,9 +11,9 @@ using CacheItemPriority = System.Web.Caching.CacheItemPriority; namespace Umbraco.Core.Cache { /// - /// Implements on top of a . + /// Implements on top of a . /// - public class ObjectCacheAppCache : IAppPolicedCache + public class ObjectCacheAppCache : IAppPolicyCache { private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); diff --git a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs index f8bba4b033..27fe4e3035 100644 --- a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs +++ b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs @@ -13,16 +13,16 @@ namespace Umbraco.Core.Cache internal abstract class RepositoryCachePolicyBase : IRepositoryCachePolicy where TEntity : class, IEntity { - private readonly IAppPolicedCache _globalCache; + private readonly IAppPolicyCache _globalCache; private readonly IScopeAccessor _scopeAccessor; - protected RepositoryCachePolicyBase(IAppPolicedCache globalCache, IScopeAccessor scopeAccessor) + protected RepositoryCachePolicyBase(IAppPolicyCache globalCache, IScopeAccessor scopeAccessor) { _globalCache = globalCache ?? throw new ArgumentNullException(nameof(globalCache)); _scopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); } - protected IAppPolicedCache Cache + protected IAppPolicyCache Cache { get { diff --git a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs index 714798a47c..9de7519edb 100644 --- a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Cache internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy where TEntity : class, IEntity { - public SingleItemsOnlyRepositoryCachePolicy(IAppPolicedCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) + public SingleItemsOnlyRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) : base(cache, scopeAccessor, options) { } diff --git a/src/Umbraco.Core/Cache/WebCachingAppCache.cs b/src/Umbraco.Core/Cache/WebCachingAppCache.cs index b762fcda07..7fbdebf9ab 100644 --- a/src/Umbraco.Core/Cache/WebCachingAppCache.cs +++ b/src/Umbraco.Core/Cache/WebCachingAppCache.cs @@ -8,11 +8,11 @@ using System.Web.Caching; namespace Umbraco.Core.Cache { /// - /// Implements on top of a . + /// Implements on top of a . /// A CacheProvider that wraps the logic of the HttpRuntime.Cache /// /// The underlying cache is expected to be HttpRuntime.Cache. - internal class WebCachingAppCache : FastDictionaryAppCacheBase, IAppPolicedCache + internal class WebCachingAppCache : FastDictionaryAppCacheBase, IAppPolicyCache { // locker object that supports upgradeable read locking // does not need to support recursion if we implement the cache correctly and ensure diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index fe277676d7..3950cf86e9 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -29,7 +29,7 @@ namespace Umbraco.Core.Composing { private const string CacheKey = "umbraco-types.list"; - private readonly IAppPolicedCache _runtimeCache; + private readonly IAppPolicyCache _runtimeCache; private readonly IProfilingLogger _logger; private readonly Dictionary _types = new Dictionary(); @@ -51,7 +51,7 @@ namespace Umbraco.Core.Composing /// The application runtime cache. /// Files storage mode. /// A profiling logger. - public TypeLoader(IAppPolicedCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger) + public TypeLoader(IAppPolicyCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger) : this(runtimeCache, localTempStorage, logger, true) { } @@ -62,7 +62,7 @@ namespace Umbraco.Core.Composing /// Files storage mode. /// A profiling logger. /// Whether to detect changes using hashes. - internal TypeLoader(IAppPolicedCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger, bool detectChanges) + internal TypeLoader(IAppPolicyCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger, bool detectChanges) { _runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); _localTempStorage = localTempStorage == LocalTempStorage.Unknown ? LocalTempStorage.Default : localTempStorage; diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index 40e99bb079..a80cd98466 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Manifest { private static readonly string Utf8Preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); - private readonly IAppPolicedCache _cache; + private readonly IAppPolicyCache _cache; private readonly ILogger _logger; private readonly ManifestValueValidatorCollection _validators; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index 6862173786..c8329d1f32 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected AppCaches AppCaches { get; } - protected IAppPolicedCache GlobalIsolatedCache => AppCaches.IsolatedCaches.GetOrCreate(); + protected IAppPolicyCache GlobalIsolatedCache => AppCaches.IsolatedCaches.GetOrCreate(); protected IScopeAccessor ScopeAccessor { get; } @@ -60,7 +60,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// Gets the isolated cache. /// /// Depends on the ambient scope cache mode. - protected IAppPolicedCache IsolatedCache + protected IAppPolicyCache IsolatedCache { get { @@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Adds or Updates an entity of type TEntity /// - /// This method is backed by an cache + /// This method is backed by an cache /// public void Save(TEntity entity) { diff --git a/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs b/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs index 8c2d277348..430c2b3d3c 100644 --- a/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs +++ b/src/Umbraco.Core/Services/Implement/LocalizedTextServiceFileSources.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Services.Implement public class LocalizedTextServiceFileSources { private readonly ILogger _logger; - private readonly IAppPolicedCache _cache; + private readonly IAppPolicyCache _cache; private readonly IEnumerable _supplementFileSources; private readonly DirectoryInfo _fileSourceFolder; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d72c0e5014..b94c718242 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -131,7 +131,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs index 5158989a8b..7483df1c44 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Cache get { return _provider; } } - internal override IAppPolicedCache RuntimeProvider + internal override IAppPolicyCache RuntimeProvider { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs b/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs index 0f649328fe..4161f576c9 100644 --- a/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs +++ b/src/Umbraco.Tests/Cache/DefaultCachePolicyTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Cache public void Caches_Single() { var isCached = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Cache [Test] public void Get_Single_From_Cache() { - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Get(It.IsAny())).Returns(new AuditItem(1, AuditType.Copy, 123, "test", "blah")); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); @@ -58,7 +58,7 @@ namespace Umbraco.Tests.Cache public void Caches_Per_Id_For_Get_All() { var cached = new List(); - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => @@ -81,7 +81,7 @@ namespace Umbraco.Tests.Cache [Test] public void Get_All_Without_Ids_From_Cache() { - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), @@ -98,7 +98,7 @@ namespace Umbraco.Tests.Cache public void If_CreateOrUpdate_Throws_Cache_Is_Removed() { var cacheCleared = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { @@ -124,7 +124,7 @@ namespace Umbraco.Tests.Cache public void If_Removes_Throws_Cache_Is_Removed() { var cacheCleared = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { diff --git a/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs b/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs index 7c5a1524d2..a4fbdf2224 100644 --- a/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs +++ b/src/Umbraco.Tests/Cache/FullDataSetCachePolicyTests.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests.Cache }; var isCached = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => @@ -60,7 +60,7 @@ namespace Umbraco.Tests.Cache new AuditItem(2, AuditType.Copy, 123, "test", "blah2") }; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Get(It.IsAny())).Returns(new AuditItem(1, AuditType.Copy, 123, "test", "blah")); var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); @@ -78,7 +78,7 @@ namespace Umbraco.Tests.Cache IList list = null; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => @@ -121,7 +121,7 @@ namespace Umbraco.Tests.Cache var cached = new List(); IList list = null; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => @@ -145,7 +145,7 @@ namespace Umbraco.Tests.Cache { var getAll = new[] { (AuditItem)null }; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Get(It.IsAny())).Returns(() => new DeepCloneableList(ListCloneBehavior.CloneOnce) { @@ -169,7 +169,7 @@ namespace Umbraco.Tests.Cache }; var cacheCleared = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { @@ -201,7 +201,7 @@ namespace Umbraco.Tests.Cache }; var cacheCleared = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) .Callback(() => { diff --git a/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs index 56f3303e9c..6297539a1b 100644 --- a/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Cache get { return _provider; } } - internal override IAppPolicedCache RuntimeProvider + internal override IAppPolicyCache RuntimeProvider { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs b/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs index 6ed7f590e0..4d34e81eff 100644 --- a/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Cache get { return _provider; } } - internal override IAppPolicedCache RuntimeProvider + internal override IAppPolicyCache RuntimeProvider { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs index 08eb5e9a60..6391e4ec7a 100644 --- a/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs @@ -8,7 +8,7 @@ namespace Umbraco.Tests.Cache public abstract class RuntimeCacheProviderTests : CacheProviderTests { - internal abstract IAppPolicedCache RuntimeProvider { get; } + internal abstract IAppPolicyCache RuntimeProvider { get; } [Test] diff --git a/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs b/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs index 2b37d85801..2525eab45b 100644 --- a/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs +++ b/src/Umbraco.Tests/Cache/SingleItemsOnlyCachePolicyTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Cache public void Get_All_Doesnt_Cache() { var cached = new List(); - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((string cacheKey, Func o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) => @@ -52,7 +52,7 @@ namespace Umbraco.Tests.Cache public void Caches_Single() { var isCached = false; - var cache = new Mock(); + var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 5b1dcde728..e293653c37 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -40,7 +40,7 @@ namespace Umbraco.Tests.PublishedContent Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes())); } - protected override TypeLoader CreateTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + protected override TypeLoader CreateTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index e798be82c4..705b2fd826 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -74,7 +74,7 @@ namespace Umbraco.Tests.PublishedContent ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType; } - protected override TypeLoader CreateTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + protected override TypeLoader CreateTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index fd617b5a21..1b3f7f50bf 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -244,7 +244,7 @@ namespace Umbraco.Tests.Testing .ComposeWebMappingProfiles(); } - protected virtual TypeLoader GetTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option) + protected virtual TypeLoader GetTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option) { switch (option) { @@ -259,13 +259,13 @@ namespace Umbraco.Tests.Testing } } - protected virtual TypeLoader CreateTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + protected virtual TypeLoader CreateTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { return CreateCommonTypeLoader(runtimeCache, globalSettings, logger); } // common to all tests = cannot be overriden - private static TypeLoader CreateCommonTypeLoader(IAppPolicedCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) + private static TypeLoader CreateCommonTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger) { return new TypeLoader(runtimeCache, globalSettings.LocalTempStorageLocation, logger, false) { diff --git a/src/Umbraco.Web/Editors/ExamineManagementController.cs b/src/Umbraco.Web/Editors/ExamineManagementController.cs index 8d930b8ed7..06334f86e7 100644 --- a/src/Umbraco.Web/Editors/ExamineManagementController.cs +++ b/src/Umbraco.Web/Editors/ExamineManagementController.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Editors { private readonly IExamineManager _examineManager; private readonly ILogger _logger; - private readonly IAppPolicedCache _runtimeCache; + private readonly IAppPolicyCache _runtimeCache; private readonly IndexRebuilder _indexRebuilder; From f952fe7aeb2acbf6ada02cf4454777e7def3b5df Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 18 Jan 2019 08:14:08 +0100 Subject: [PATCH 194/223] More renaming of caches --- ...derExtensions.cs => AppCacheExtensions.cs} | 2 +- src/Umbraco.Core/Cache/ObjectCacheAppCache.cs | 2 +- src/Umbraco.Core/Cache/WebCachingAppCache.cs | 1 - src/Umbraco.Core/Composing/Current.cs | 2 +- .../Implement/MemberGroupRepository.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- ...CacheProviderTests.cs => AppCacheTests.cs} | 98 +++++++++---------- ...iderTests.cs => DeepCloneAppCacheTests.cs} | 7 +- ...erTests.cs => HttpRequestAppCacheTests.cs} | 8 +- .../Cache/HttpRuntimeCacheProviderTests.cs | 59 ----------- ...roviderTests.cs => ObjectAppCacheTests.cs} | 6 +- .../PublishedContentCacheTests.cs | 8 +- ...oviderTests.cs => RuntimeAppCacheTests.cs} | 16 ++- .../Cache/WebCachingAppCacheTests.cs | 50 ++++++++++ .../Scoping/ScopedRepositoryTests.cs | 6 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 12 +-- .../Cache/ContentCacheRefresher.cs | 2 +- src/Umbraco.Web/Cache/MediaCacheRefresher.cs | 2 +- src/Umbraco.Web/Composing/Current.cs | 2 +- .../Dictionary/UmbracoCultureDictionary.cs | 20 ++-- .../Editors/CurrentUserController.cs | 2 +- src/Umbraco.Web/HtmlHelperRenderExtensions.cs | 2 +- src/Umbraco.Web/Macros/MacroRenderer.cs | 4 +- .../DictionaryPublishedContent.cs | 6 +- .../PublishedContentCache.cs | 16 +-- .../XmlPublishedCache/PublishedMediaCache.cs | 22 ++--- .../XmlPublishedCache/XmlPublishedContent.cs | 12 +-- 27 files changed, 178 insertions(+), 193 deletions(-) rename src/Umbraco.Core/Cache/{CacheProviderExtensions.cs => AppCacheExtensions.cs} (98%) rename src/Umbraco.Tests/Cache/{CacheProviderTests.cs => AppCacheTests.cs} (69%) rename src/Umbraco.Tests/Cache/{DeepCloneRuntimeCacheProviderTests.cs => DeepCloneAppCacheTests.cs} (94%) rename src/Umbraco.Tests/Cache/{HttpRequestCacheProviderTests.cs => HttpRequestAppCacheTests.cs} (82%) delete mode 100644 src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs rename src/Umbraco.Tests/Cache/{ObjectCacheProviderTests.cs => ObjectAppCacheTests.cs} (78%) rename src/Umbraco.Tests/Cache/{RuntimeCacheProviderTests.cs => RuntimeAppCacheTests.cs} (51%) create mode 100644 src/Umbraco.Tests/Cache/WebCachingAppCacheTests.cs diff --git a/src/Umbraco.Core/Cache/CacheProviderExtensions.cs b/src/Umbraco.Core/Cache/AppCacheExtensions.cs similarity index 98% rename from src/Umbraco.Core/Cache/CacheProviderExtensions.cs rename to src/Umbraco.Core/Cache/AppCacheExtensions.cs index d943d19edb..ddba8be1b2 100644 --- a/src/Umbraco.Core/Cache/CacheProviderExtensions.cs +++ b/src/Umbraco.Core/Cache/AppCacheExtensions.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Cache /// /// Extensions for strongly typed access /// - public static class CacheProviderExtensions + public static class AppCacheExtensions { public static T GetCacheItem(this IAppPolicyCache provider, string cacheKey, diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs index 449eb5d643..5c4f76f51d 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs @@ -105,7 +105,7 @@ namespace Umbraco.Core.Cache /// public object Get(string key, Func factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) { - // see notes in HttpRuntimeCacheProvider + // see notes in HttpRuntimeAppCache Lazy result; diff --git a/src/Umbraco.Core/Cache/WebCachingAppCache.cs b/src/Umbraco.Core/Cache/WebCachingAppCache.cs index 7fbdebf9ab..c6e104221a 100644 --- a/src/Umbraco.Core/Cache/WebCachingAppCache.cs +++ b/src/Umbraco.Core/Cache/WebCachingAppCache.cs @@ -9,7 +9,6 @@ namespace Umbraco.Core.Cache { /// /// Implements on top of a . - /// A CacheProvider that wraps the logic of the HttpRuntime.Cache /// /// The underlying cache is expected to be HttpRuntime.Cache. internal class WebCachingAppCache : FastDictionaryAppCacheBase, IAppPolicyCache diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index bfc5cfd51c..429fee3317 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -180,7 +180,7 @@ namespace Umbraco.Core.Composing public static ICultureDictionaryFactory CultureDictionaryFactory => Factory.GetInstance(); - public static AppCaches ApplicationCache + public static AppCaches AppCaches => Factory.GetInstance(); public static ServiceContext Services diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs index 11166ce777..e6ee79470c 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberGroupRepository.cs @@ -124,7 +124,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var result = Get(qry); return result.FirstOrDefault(); }, - //cache for 5 mins since that is the default in the RuntimeCacheProvider + //cache for 5 mins since that is the default in the Runtime app cache TimeSpan.FromMinutes(5), //sliding is true true); diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b94c718242..5b2692359a 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -114,7 +114,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/CacheProviderTests.cs b/src/Umbraco.Tests/Cache/AppCacheTests.cs similarity index 69% rename from src/Umbraco.Tests/Cache/CacheProviderTests.cs rename to src/Umbraco.Tests/Cache/AppCacheTests.cs index f2288cbaf2..f18e08d680 100644 --- a/src/Umbraco.Tests/Cache/CacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/AppCacheTests.cs @@ -7,9 +7,9 @@ using umbraco; namespace Umbraco.Tests.Cache { - public abstract class CacheProviderTests + public abstract class AppCacheTests { - internal abstract IAppCache Provider { get; } + internal abstract IAppCache AppCache { get; } protected abstract int GetTotalItemCount { get; } [SetUp] @@ -21,22 +21,22 @@ namespace Umbraco.Tests.Cache [TearDown] public virtual void TearDown() { - Provider.Clear(); + AppCache.Clear(); } [Test] public void Throws_On_Reentry() { // don't run for StaticCacheProvider - not making sense - if (GetType() == typeof (StaticCacheProviderTests)) + if (GetType() == typeof (StaticAppCacheTests)) Assert.Ignore("Do not run for StaticCacheProvider."); Exception exception = null; - var result = Provider.Get("blah", () => + var result = AppCache.Get("blah", () => { try { - var result2 = Provider.Get("blah"); + var result2 = AppCache.Get("blah"); } catch (Exception e) { @@ -56,7 +56,7 @@ namespace Umbraco.Tests.Cache object result; try { - result = Provider.Get("Blah", () => + result = AppCache.Get("Blah", () => { counter++; throw new Exception("Do not cache this"); @@ -66,7 +66,7 @@ namespace Umbraco.Tests.Cache try { - result = Provider.Get("Blah", () => + result = AppCache.Get("Blah", () => { counter++; throw new Exception("Do not cache this"); @@ -85,13 +85,13 @@ namespace Umbraco.Tests.Cache object result; - result = Provider.Get("Blah", () => + result = AppCache.Get("Blah", () => { counter++; return ""; }); - result = Provider.Get("Blah", () => + result = AppCache.Get("Blah", () => { counter++; return ""; @@ -108,14 +108,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("Test1", () => cacheContent1); - Provider.Get("Tester2", () => cacheContent2); - Provider.Get("Tes3", () => cacheContent3); - Provider.Get("different4", () => cacheContent4); + AppCache.Get("Test1", () => cacheContent1); + AppCache.Get("Tester2", () => cacheContent2); + AppCache.Get("Tes3", () => cacheContent3); + AppCache.Get("different4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - var result = Provider.SearchByKey("Tes"); + var result = AppCache.SearchByKey("Tes"); Assert.AreEqual(3, result.Count()); } @@ -127,14 +127,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("TTes1t", () => cacheContent1); - Provider.Get("Tester2", () => cacheContent2); - Provider.Get("Tes3", () => cacheContent3); - Provider.Get("different4", () => cacheContent4); + AppCache.Get("TTes1t", () => cacheContent1); + AppCache.Get("Tester2", () => cacheContent2); + AppCache.Get("Tes3", () => cacheContent3); + AppCache.Get("different4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearByRegex("^\\w+es\\d.*"); + AppCache.ClearByRegex("^\\w+es\\d.*"); Assert.AreEqual(2, GetTotalItemCount); } @@ -146,14 +146,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("Test1", () => cacheContent1); - Provider.Get("Tester2", () => cacheContent2); - Provider.Get("Tes3", () => cacheContent3); - Provider.Get("different4", () => cacheContent4); + AppCache.Get("Test1", () => cacheContent1); + AppCache.Get("Tester2", () => cacheContent2); + AppCache.Get("Tes3", () => cacheContent3); + AppCache.Get("different4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearByKey("Test"); + AppCache.ClearByKey("Test"); Assert.AreEqual(2, GetTotalItemCount); } @@ -165,15 +165,15 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("Test1", () => cacheContent1); - Provider.Get("Test2", () => cacheContent2); - Provider.Get("Test3", () => cacheContent3); - Provider.Get("Test4", () => cacheContent4); + AppCache.Get("Test1", () => cacheContent1); + AppCache.Get("Test2", () => cacheContent2); + AppCache.Get("Test3", () => cacheContent3); + AppCache.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.Clear("Test1"); - Provider.Clear("Test2"); + AppCache.Clear("Test1"); + AppCache.Clear("Test2"); Assert.AreEqual(2, GetTotalItemCount); } @@ -185,14 +185,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("Test1", () => cacheContent1); - Provider.Get("Test2", () => cacheContent2); - Provider.Get("Test3", () => cacheContent3); - Provider.Get("Test4", () => cacheContent4); + AppCache.Get("Test1", () => cacheContent1); + AppCache.Get("Test2", () => cacheContent2); + AppCache.Get("Test3", () => cacheContent3); + AppCache.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.Clear(); + AppCache.Clear(); Assert.AreEqual(0, GetTotalItemCount); } @@ -201,7 +201,7 @@ namespace Umbraco.Tests.Cache public void Can_Add_When_Not_Available() { var cacheContent1 = new MacroCacheContent(new LiteralControl(), "Test1"); - Provider.Get("Test1", () => cacheContent1); + AppCache.Get("Test1", () => cacheContent1); Assert.AreEqual(1, GetTotalItemCount); } @@ -209,8 +209,8 @@ namespace Umbraco.Tests.Cache public void Can_Get_When_Available() { var cacheContent1 = new MacroCacheContent(new LiteralControl(), "Test1"); - var result = Provider.Get("Test1", () => cacheContent1); - var result2 = Provider.Get("Test1", () => cacheContent1); + var result = AppCache.Get("Test1", () => cacheContent1); + var result2 = AppCache.Get("Test1", () => cacheContent1); Assert.AreEqual(1, GetTotalItemCount); Assert.AreEqual(result, result2); } @@ -222,15 +222,15 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("Test1", () => cacheContent1); - Provider.Get("Test2", () => cacheContent2); - Provider.Get("Test3", () => cacheContent3); - Provider.Get("Test4", () => cacheContent4); + AppCache.Get("Test1", () => cacheContent1); + AppCache.Get("Test2", () => cacheContent2); + AppCache.Get("Test3", () => cacheContent3); + AppCache.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); //Provider.ClearCacheObjectTypes("umbraco.MacroCacheContent"); - Provider.ClearOfType(typeof(MacroCacheContent).ToString()); + AppCache.ClearOfType(typeof(MacroCacheContent).ToString()); Assert.AreEqual(1, GetTotalItemCount); } @@ -242,14 +242,14 @@ namespace Umbraco.Tests.Cache var cacheContent2 = new MacroCacheContent(new LiteralControl(), "Test2"); var cacheContent3 = new MacroCacheContent(new LiteralControl(), "Test3"); var cacheContent4 = new LiteralControl(); - Provider.Get("Test1", () => cacheContent1); - Provider.Get("Test2", () => cacheContent2); - Provider.Get("Test3", () => cacheContent3); - Provider.Get("Test4", () => cacheContent4); + AppCache.Get("Test1", () => cacheContent1); + AppCache.Get("Test2", () => cacheContent2); + AppCache.Get("Test3", () => cacheContent3); + AppCache.Get("Test4", () => cacheContent4); Assert.AreEqual(4, GetTotalItemCount); - Provider.ClearOfType(); + AppCache.ClearOfType(); Assert.AreEqual(1, GetTotalItemCount); } diff --git a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs similarity index 94% rename from src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs rename to src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs index 7483df1c44..11e2c56873 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs @@ -8,13 +8,12 @@ using Umbraco.Core.Cache; using Umbraco.Core.Collections; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Tests.Collections; namespace Umbraco.Tests.Cache { [TestFixture] - public class DeepCloneRuntimeCacheProviderTests : RuntimeCacheProviderTests + public class DeepCloneAppCacheTests : RuntimeAppCacheTests { private DeepCloneAppCache _provider; @@ -29,12 +28,12 @@ namespace Umbraco.Tests.Cache _provider = new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache)); } - internal override IAppCache Provider + internal override IAppCache AppCache { get { return _provider; } } - internal override IAppPolicyCache RuntimeProvider + internal override IAppPolicyCache AppPolicyCache { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs similarity index 82% rename from src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs rename to src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs index f442319d7f..635155f68e 100644 --- a/src/Umbraco.Tests/Cache/HttpRequestCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs @@ -5,7 +5,7 @@ using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Cache { [TestFixture] - public class HttpRequestCacheProviderTests : CacheProviderTests + public class HttpRequestAppCacheTests : AppCacheTests { private HttpRequestAppCache _provider; private FakeHttpContextFactory _ctx; @@ -17,7 +17,7 @@ namespace Umbraco.Tests.Cache _provider = new HttpRequestAppCache(_ctx.HttpContext); } - internal override IAppCache Provider + internal override IAppCache AppCache { get { return _provider; } } @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Cache } [TestFixture] - public class StaticCacheProviderTests : CacheProviderTests + public class StaticAppCacheTests : AppCacheTests { private DictionaryCacheProvider _provider; @@ -39,7 +39,7 @@ namespace Umbraco.Tests.Cache _provider = new DictionaryCacheProvider(); } - internal override IAppCache Provider + internal override IAppCache AppCache { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs deleted file mode 100644 index 6297539a1b..0000000000 --- a/src/Umbraco.Tests/Cache/HttpRuntimeCacheProviderTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Diagnostics; -using System.Web; -using NUnit.Framework; -using Umbraco.Core.Cache; - -namespace Umbraco.Tests.Cache -{ - [TestFixture] - public class HttpRuntimeCacheProviderTests : RuntimeCacheProviderTests - { - private WebCachingAppCache _provider; - - protected override int GetTotalItemCount - { - get { return HttpRuntime.Cache.Count; } - } - - public override void Setup() - { - base.Setup(); - _provider = new WebCachingAppCache(HttpRuntime.Cache); - } - - internal override IAppCache Provider - { - get { return _provider; } - } - - internal override IAppPolicyCache RuntimeProvider - { - get { return _provider; } - } - - [Test] - public void DoesNotCacheExceptions() - { - string value; - Assert.Throws(() => { value = (string)_provider.Get("key", () => GetValue(1)); }); - Assert.Throws(() => { value = (string)_provider.Get("key", () => GetValue(2)); }); - - // does not throw - value = (string)_provider.Get("key", () => GetValue(3)); - Assert.AreEqual("succ3", value); - - // cache - value = (string)_provider.Get("key", () => GetValue(4)); - Assert.AreEqual("succ3", value); - } - - private static string GetValue(int i) - { - Debug.Print("get" + i); - if (i < 3) - throw new Exception("fail"); - return "succ" + i; - } - } -} diff --git a/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs b/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs similarity index 78% rename from src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs rename to src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs index 4d34e81eff..b9c729f891 100644 --- a/src/Umbraco.Tests/Cache/ObjectCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Cache; namespace Umbraco.Tests.Cache { [TestFixture] - public class ObjectCacheProviderTests : RuntimeCacheProviderTests + public class ObjectAppCacheTests : RuntimeAppCacheTests { private ObjectCacheAppCache _provider; @@ -23,12 +23,12 @@ namespace Umbraco.Tests.Cache _provider = new ObjectCacheAppCache(); } - internal override IAppCache Provider + internal override IAppCache AppCache { get { return _provider; } } - internal override IAppPolicyCache RuntimeProvider + internal override IAppPolicyCache AppPolicyCache { get { return _provider; } } diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 79d0dfb9da..f740637602 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -63,12 +63,12 @@ namespace Umbraco.Tests.Cache.PublishedCache _xml = new XmlDocument(); _xml.LoadXml(GetXml()); var xmlStore = new XmlStore(() => _xml, null, null, null); - var cacheProvider = new DictionaryCacheProvider(); + var appCache = new DictionaryCacheProvider(); var domainCache = new DomainCache(ServiceContext.DomainService, DefaultCultureAccessor); var publishedShapshot = new Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedSnapshot( - new PublishedContentCache(xmlStore, domainCache, cacheProvider, globalSettings, new SiteDomainHelper(), ContentTypesCache, null, null), - new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, cacheProvider, ContentTypesCache, Factory.GetInstance()), - new PublishedMemberCache(null, cacheProvider, Current.Services.MemberService, ContentTypesCache), + new PublishedContentCache(xmlStore, domainCache, appCache, globalSettings, new SiteDomainHelper(), ContentTypesCache, null, null), + new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, appCache, ContentTypesCache, Factory.GetInstance()), + new PublishedMemberCache(null, appCache, Current.Services.MemberService, ContentTypesCache), domainCache); var publishedSnapshotService = new Mock(); publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedShapshot); diff --git a/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/RuntimeAppCacheTests.cs similarity index 51% rename from src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs rename to src/Umbraco.Tests/Cache/RuntimeAppCacheTests.cs index 6391e4ec7a..1beeae74db 100644 --- a/src/Umbraco.Tests/Cache/RuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/RuntimeAppCacheTests.cs @@ -5,25 +5,23 @@ using Umbraco.Core.Cache; namespace Umbraco.Tests.Cache { - public abstract class RuntimeCacheProviderTests : CacheProviderTests + public abstract class RuntimeAppCacheTests : AppCacheTests { - - internal abstract IAppPolicyCache RuntimeProvider { get; } - + internal abstract IAppPolicyCache AppPolicyCache { get; } [Test] [Explicit("Testing for timeouts cannot work on VSTS.")] public void Can_Add_And_Expire_Struct_Strongly_Typed_With_Null() { var now = DateTime.Now; - RuntimeProvider.Insert("DateTimeTest", () => now, new TimeSpan(0, 0, 0, 0, 200)); - Assert.AreEqual(now, Provider.GetCacheItem("DateTimeTest")); - Assert.AreEqual(now, Provider.GetCacheItem("DateTimeTest")); + AppPolicyCache.Insert("DateTimeTest", () => now, new TimeSpan(0, 0, 0, 0, 200)); + Assert.AreEqual(now, AppCache.GetCacheItem("DateTimeTest")); + Assert.AreEqual(now, AppCache.GetCacheItem("DateTimeTest")); Thread.Sleep(300); //sleep longer than the cache expiration - Assert.AreEqual(default(DateTime), Provider.GetCacheItem("DateTimeTest")); - Assert.AreEqual(null, Provider.GetCacheItem("DateTimeTest")); + Assert.AreEqual(default(DateTime), AppCache.GetCacheItem("DateTimeTest")); + Assert.AreEqual(null, AppCache.GetCacheItem("DateTimeTest")); } } } diff --git a/src/Umbraco.Tests/Cache/WebCachingAppCacheTests.cs b/src/Umbraco.Tests/Cache/WebCachingAppCacheTests.cs new file mode 100644 index 0000000000..e732ae5766 --- /dev/null +++ b/src/Umbraco.Tests/Cache/WebCachingAppCacheTests.cs @@ -0,0 +1,50 @@ +using System; +using System.Diagnostics; +using System.Web; +using NUnit.Framework; +using Umbraco.Core.Cache; + +namespace Umbraco.Tests.Cache +{ + [TestFixture] + public class WebCachingAppCacheTests : RuntimeAppCacheTests + { + private WebCachingAppCache _appCache; + + protected override int GetTotalItemCount => HttpRuntime.Cache.Count; + + public override void Setup() + { + base.Setup(); + _appCache = new WebCachingAppCache(HttpRuntime.Cache); + } + + internal override IAppCache AppCache => _appCache; + + internal override IAppPolicyCache AppPolicyCache => _appCache; + + [Test] + public void DoesNotCacheExceptions() + { + string value; + Assert.Throws(() => { value = (string)_appCache.Get("key", () => GetValue(1)); }); + Assert.Throws(() => { value = (string)_appCache.Get("key", () => GetValue(2)); }); + + // does not throw + value = (string)_appCache.Get("key", () => GetValue(3)); + Assert.AreEqual("succ3", value); + + // cache + value = (string)_appCache.Get("key", () => GetValue(4)); + Assert.AreEqual("succ3", value); + } + + private static string GetValue(int i) + { + Debug.Print("get" + i); + if (i < 3) + throw new Exception("fail"); + return "succ" + i; + } + } +} diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index 12cd02d2e9..c56ec57db0 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -60,7 +60,7 @@ namespace Umbraco.Tests.Scoping { var scopeProvider = ScopeProvider; var service = Current.Services.UserService; - var globalCache = Current.ApplicationCache.IsolatedCaches.GetOrCreate(typeof(IUser)); + var globalCache = Current.AppCaches.IsolatedCaches.GetOrCreate(typeof(IUser)); var user = (IUser)new User("name", "email", "username", "rawPassword"); service.Save(user); @@ -137,7 +137,7 @@ namespace Umbraco.Tests.Scoping { var scopeProvider = ScopeProvider; var service = Current.Services.LocalizationService; - var globalCache = Current.ApplicationCache.IsolatedCaches.GetOrCreate(typeof (ILanguage)); + var globalCache = Current.AppCaches.IsolatedCaches.GetOrCreate(typeof (ILanguage)); var lang = (ILanguage) new Language("fr-FR"); service.Save(lang); @@ -229,7 +229,7 @@ namespace Umbraco.Tests.Scoping { var scopeProvider = ScopeProvider; var service = Current.Services.LocalizationService; - var globalCache = Current.ApplicationCache.IsolatedCaches.GetOrCreate(typeof (IDictionaryItem)); + var globalCache = Current.AppCaches.IsolatedCaches.GetOrCreate(typeof (IDictionaryItem)); var lang = (ILanguage)new Language("fr-FR"); service.Save(lang); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e49ba250fa..a2d33a1f31 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -225,7 +225,7 @@ - + @@ -286,11 +286,11 @@ - - - - - + + + + + diff --git a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs index 36397540b6..3f2ef1620c 100644 --- a/src/Umbraco.Web/Cache/ContentCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentCacheRefresher.cs @@ -102,7 +102,7 @@ namespace Umbraco.Web.Cache if (payloads.Any(x => x.ChangeTypes.HasType(TreeChangeTypes.RefreshAll)) || publishedChanged) { // when a public version changes - Current.ApplicationCache.ClearPartialViewCache(); + Current.AppCaches.ClearPartialViewCache(); MacroCacheRefresher.ClearMacroContentCache(AppCaches); // just the content } diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index cdaf43dac3..fc62d38e62 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -47,7 +47,7 @@ namespace Umbraco.Web.Cache if (anythingChanged) { - Current.ApplicationCache.ClearPartialViewCache(); + Current.AppCaches.ClearPartialViewCache(); var mediaCache = AppCaches.IsolatedCaches.Get(); diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index ed1853c351..8759193964 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -203,7 +203,7 @@ namespace Umbraco.Web.Composing public static IProfilingLogger ProfilingLogger => CoreCurrent.ProfilingLogger; - public static AppCaches ApplicationCache => CoreCurrent.ApplicationCache; + public static AppCaches AppCaches => CoreCurrent.AppCaches; public static ServiceContext Services => CoreCurrent.Services; diff --git a/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs b/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs index 5234bf9fa7..6e1c35352a 100644 --- a/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs +++ b/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs @@ -21,31 +21,29 @@ namespace Umbraco.Web.Dictionary public class DefaultCultureDictionary : Core.Dictionary.ICultureDictionary { private readonly ILocalizationService _localizationService; - private readonly IAppCache _requestCacheProvider; + private readonly IAppCache _requestCache; private readonly CultureInfo _specificCulture; public DefaultCultureDictionary() - : this(Current.Services.LocalizationService, Current.ApplicationCache.RequestCache) - { + : this(Current.Services.LocalizationService, Current.AppCaches.RequestCache) + { } - } - - public DefaultCultureDictionary(ILocalizationService localizationService, IAppCache requestCacheProvider) + public DefaultCultureDictionary(ILocalizationService localizationService, IAppCache requestCache) { _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); - _requestCacheProvider = requestCacheProvider ?? throw new ArgumentNullException(nameof(requestCacheProvider)); + _requestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache)); } public DefaultCultureDictionary(CultureInfo specificCulture) - : this(Current.Services.LocalizationService, Current.ApplicationCache.RequestCache) + : this(Current.Services.LocalizationService, Current.AppCaches.RequestCache) { _specificCulture = specificCulture ?? throw new ArgumentNullException(nameof(specificCulture)); } - public DefaultCultureDictionary(CultureInfo specificCulture, ILocalizationService localizationService, IAppCache requestCacheProvider) + public DefaultCultureDictionary(CultureInfo specificCulture, ILocalizationService localizationService, IAppCache requestCache) { _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); - _requestCacheProvider = requestCacheProvider ?? throw new ArgumentNullException(nameof(requestCacheProvider)); + _requestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache)); _specificCulture = specificCulture ?? throw new ArgumentNullException(nameof(specificCulture)); } @@ -123,7 +121,7 @@ namespace Umbraco.Web.Dictionary { //ensure it's stored/retrieved from request cache //NOTE: This is no longer necessary since these are cached at the runtime level, but we can leave it here for now. - return _requestCacheProvider.GetCacheItem(typeof (DefaultCultureDictionary).Name + "Culture" + Culture.Name, + return _requestCache.GetCacheItem(typeof (DefaultCultureDictionary).Name + "Culture" + Culture.Name, () => _localizationService.GetLanguageByIsoCode(Culture.Name)); } } diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs index b0f4af0f57..02470e8ea1 100644 --- a/src/Umbraco.Web/Editors/CurrentUserController.cs +++ b/src/Umbraco.Web/Editors/CurrentUserController.cs @@ -157,7 +157,7 @@ namespace Umbraco.Web.Editors public async Task PostSetAvatar() { //borrow the logic from the user controller - return await UsersController.PostSetAvatarInternal(Request, Services.UserService, Current.ApplicationCache.StaticCache, Security.GetUserId().ResultOr(0)); + return await UsersController.PostSetAvatarInternal(Request, Services.UserService, Current.AppCaches.StaticCache, Security.GetUserId().ResultOr(0)); } /// diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index 9c30f74ea7..626a19a369 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -105,7 +105,7 @@ namespace Umbraco.Web var contextualKey = contextualKeyBuilder(model, viewData); cacheKey.AppendFormat("c{0}-", contextualKey); } - return Current.ApplicationCache.CachedPartialView(htmlHelper, partialViewName, model, cachedSeconds, cacheKey.ToString(), viewData); + return Current.AppCaches.CachedPartialView(htmlHelper, partialViewName, model, cachedSeconds, cacheKey.ToString(), viewData); } public static MvcHtmlString EditorFor(this HtmlHelper htmlHelper, string templateName = "", string htmlFieldName = "", object additionalViewData = null) diff --git a/src/Umbraco.Web/Macros/MacroRenderer.cs b/src/Umbraco.Web/Macros/MacroRenderer.cs index 0bcdb3225b..b7187da743 100755 --- a/src/Umbraco.Web/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web/Macros/MacroRenderer.cs @@ -94,7 +94,7 @@ namespace Umbraco.Web.Macros // only if cache is enabled if (UmbracoContext.Current.InPreviewMode || model.CacheDuration <= 0) return null; - var cache = Current.ApplicationCache.RuntimeCache; + var cache = Current.AppCaches.RuntimeCache; var macroContent = cache.GetCacheItem(CacheKeys.MacroContentCacheKey + model.CacheIdentifier); if (macroContent == null) return null; @@ -151,7 +151,7 @@ namespace Umbraco.Web.Macros // remember when we cache the content macroContent.Date = DateTime.Now; - var cache = Current.ApplicationCache.RuntimeCache; + var cache = Current.AppCaches.RuntimeCache; cache.Insert( CacheKeys.MacroContentCacheKey + model.CacheIdentifier, () => macroContent, diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index e040e7e926..83bd84dab6 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -35,7 +35,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache Func getParent, Func> getChildren, Func getProperty, - IAppCache cacheProvider, + IAppCache appCache, PublishedContentTypeCache contentTypeCache, XPathNavigator nav, bool fromExamine) @@ -47,7 +47,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _getParent = new Lazy(() => getParent(ParentId)); _getChildren = new Lazy>(() => getChildren(Id, nav)); _getProperty = getProperty; - _cacheProvider = cacheProvider; + _appCache = appCache; LoadedFromExamine = fromExamine; @@ -133,7 +133,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache //private readonly Func> _getChildren; private readonly Lazy> _getChildren; private readonly Func _getProperty; - private readonly IAppCache _cacheProvider; + private readonly IAppCache _appCache; /// /// Returns 'Media' as the item type diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index 67813ce9f6..d8c7c41ea1 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -15,7 +15,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { internal class PublishedContentCache : PublishedCacheBase, IPublishedContentCache { - private readonly IAppCache _cacheProvider; + private readonly IAppCache _appCache; private readonly IGlobalSettings _globalSettings; private readonly RoutesCache _routesCache; private readonly IDomainCache _domainCache; @@ -24,13 +24,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // initialize a PublishedContentCache instance with // an XmlStore containing the master xml - // an ICacheProvider that should be at request-level + // an IAppCache that should be at request-level // a RoutesCache - need to cleanup that one // a preview token string (or null if not previewing) public PublishedContentCache( XmlStore xmlStore, // an XmlStore containing the master xml IDomainCache domainCache, // an IDomainCache implementation - IAppCache cacheProvider, // an ICacheProvider that should be at request-level + IAppCache appCache, // an IAppCache that should be at request-level IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, PublishedContentTypeCache contentTypeCache, // a PublishedContentType cache @@ -38,7 +38,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache string previewToken) // a preview token string (or null if not previewing) : base(previewToken.IsNullOrWhiteSpace() == false) { - _cacheProvider = cacheProvider; + _appCache = appCache; _globalSettings = globalSettings; _routesCache = routesCache; // may be null for unit-testing _contentTypeCache = contentTypeCache; @@ -315,13 +315,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private IPublishedContent ConvertToDocument(XmlNode xmlNode, bool isPreviewing) { - return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _cacheProvider, _contentTypeCache); + return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache); } private IEnumerable ConvertToDocuments(XmlNodeList xmlNodes, bool isPreviewing) { return xmlNodes.Cast() - .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _cacheProvider, _contentTypeCache)); + .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache)); } #endregion @@ -517,8 +517,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // clear recursive properties cached by XmlPublishedContent.GetProperty // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch) // NOTE also clears all the media cache properties, which is OK (see media cache) - _cacheProvider.ClearOfType(); - //_cacheProvider.ClearCacheByKeySearch("XmlPublishedCache.PublishedContentCache:RecursiveProperty-"); + _appCache.ClearOfType(); + //_appCache.ClearCacheByKeySearch("XmlPublishedCache.PublishedContentCache:RecursiveProperty-"); } #endregion diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index 3ead5a5166..dadf40a33b 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -43,15 +43,15 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IEntityXmlSerializer _entitySerializer; // must be specified by the ctor - private readonly IAppCache _cacheProvider; + private readonly IAppCache _appCache; - public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) + public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); - _cacheProvider = cacheProvider; + _appCache = appCache; _xmlStore = xmlStore; _contentTypeCache = contentTypeCache; _entitySerializer = entitySerializer; @@ -63,16 +63,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// /// /// - /// + /// /// /// - internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) + internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _searchProvider = searchProvider ?? throw new ArgumentNullException(nameof(searchProvider)); - _cacheProvider = cacheProvider; + _appCache = appCache; _contentTypeCache = contentTypeCache; _entitySerializer = entitySerializer; } @@ -598,8 +598,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // clear recursive properties cached by XmlPublishedContent.GetProperty // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch) // NOTE all properties cleared when clearing the content cache (see content cache) - //_cacheProvider.ClearCacheObjectTypes(); - //_cacheProvider.ClearCacheByKeySearch("XmlPublishedCache.PublishedMediaCache:RecursiveProperty-"); + //_appCache.ClearCacheObjectTypes(); + //_appCache.ClearCacheByKeySearch("XmlPublishedCache.PublishedMediaCache:RecursiveProperty-"); } #region Content types @@ -663,7 +663,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache parentId => parentId < 0 ? null : GetUmbracoMedia(parentId), GetChildrenMedia, GetProperty, - _cacheProvider, + _appCache, _contentTypeCache, cacheValues.XPath, // though, outside of tests, that should be null cacheValues.FromExamine @@ -676,14 +676,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache if (_publishedMediaCacheEnabled == false) return func(id); - var cache = Current.ApplicationCache.RuntimeCache; + var cache = Current.AppCaches.RuntimeCache; var key = PublishedMediaCacheKey + id; return (CacheValues)cache.Get(key, () => func(id), _publishedMediaCacheTimespan); } internal static void ClearCache(int id) { - var cache = Current.ApplicationCache.RuntimeCache; + var cache = Current.AppCaches.RuntimeCache; var sid = id.ToString(); var key = PublishedMediaCacheKey + sid; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index a313d6947d..eb54c85984 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -20,18 +20,18 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache [XmlType(Namespace = "http://umbraco.org/webservices/")] internal class XmlPublishedContent : PublishedContentBase { - private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache) + private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, IAppCache appCache, PublishedContentTypeCache contentTypeCache) { _xmlNode = xmlNode; _isPreviewing = isPreviewing; - _cacheProvider = cacheProvider; + _appCache = appCache; _contentTypeCache = contentTypeCache; } private readonly XmlNode _xmlNode; private readonly bool _isPreviewing; - private readonly IAppCache _cacheProvider; // at snapshot/request level (see PublishedContentCache) + private readonly IAppCache _appCache; // at snapshot/request level (see PublishedContentCache) private readonly PublishedContentTypeCache _contentTypeCache; private readonly object _initializeLock = new object(); @@ -252,7 +252,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache if (parent == null) return; if (parent.Attributes?.GetNamedItem("isDoc") != null) - _parent = Get(parent, _isPreviewing, _cacheProvider, _contentTypeCache); + _parent = Get(parent, _isPreviewing, _appCache, _contentTypeCache); _parentInitialized = true; } @@ -409,7 +409,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var iterator = nav.Select(expr); _children = iterator.Cast() - .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _cacheProvider, _contentTypeCache)) + .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _appCache, _contentTypeCache)) .OrderBy(x => x.SortOrder) .ToList(); @@ -440,7 +440,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public static void ClearRequest() { - Current.ApplicationCache.RequestCache.ClearByKey(CacheKeyPrefix); + Current.AppCaches.RequestCache.ClearByKey(CacheKeyPrefix); } private const string CacheKeyPrefix = "CONTENTCACHE_XMLPUBLISHEDCONTENT_"; From ec58532f7bf70b055703b18bc7ded1e2278bfe1c Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 18 Jan 2019 08:29:16 +0100 Subject: [PATCH 195/223] More renaming of caches --- src/Umbraco.Core/Cache/AppCaches.cs | 6 +++--- ...CacheProvider.cs => DictionaryAppCache.cs} | 2 +- ...eProvider.cs => FastDictionaryAppCache.cs} | 2 +- src/Umbraco.Core/Runtime/CoreRuntime.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 4 ++-- src/Umbraco.Tests/Cache/AppCacheTests.cs | 6 +++--- .../Cache/HttpRequestAppCacheTests.cs | 16 +++++++-------- .../PublishedContentCacheTests.cs | 2 +- .../PublishedMediaCacheTests.cs | 8 ++++---- src/Umbraco.Tests/Macros/MacroTests.cs | 2 +- .../Repositories/DocumentRepositoryTest.cs | 4 ++-- .../Repositories/MediaRepositoryTest.cs | 4 ++-- .../Published/PropertyCacheLevelTests.cs | 4 ++-- .../PublishedContent/PublishedMediaTests.cs | 20 +++++++++---------- .../Scoping/ScopedRepositoryTests.cs | 2 +- .../NuCache/PublishedSnapshotService.cs | 13 ++++++------ .../XmlPublishedCache/PublishedMemberCache.cs | 4 ++-- .../XmlPublishedCache/XmlPublishedContent.cs | 6 +++--- src/Umbraco.Web/Runtime/WebRuntime.cs | 2 +- 19 files changed, 55 insertions(+), 54 deletions(-) rename src/Umbraco.Core/Cache/{DictionaryCacheProvider.cs => DictionaryAppCache.cs} (98%) rename src/Umbraco.Core/Cache/{FastDictionaryCacheProvider.cs => FastDictionaryAppCache.cs} (99%) diff --git a/src/Umbraco.Core/Cache/AppCaches.cs b/src/Umbraco.Core/Cache/AppCaches.cs index 7e5fa43682..d81e79f7d8 100644 --- a/src/Umbraco.Core/Cache/AppCaches.cs +++ b/src/Umbraco.Core/Cache/AppCaches.cs @@ -21,7 +21,7 @@ namespace Umbraco.Core.Cache public AppCaches(System.Web.Caching.Cache cache) : this( new WebCachingAppCache(cache), - new DictionaryCacheProvider(), + new DictionaryAppCache(), new HttpRequestAppCache(), new IsolatedCaches(t => new ObjectCacheAppCache())) { } @@ -31,12 +31,12 @@ namespace Umbraco.Core.Cache /// public AppCaches( IAppPolicyCache runtimeCache, - IAppCache staticCacheProvider, + IAppCache staticCache, IAppCache requestCache, IsolatedCaches isolatedCaches) { RuntimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); - StaticCache = staticCacheProvider ?? throw new ArgumentNullException(nameof(staticCacheProvider)); + StaticCache = staticCache ?? throw new ArgumentNullException(nameof(staticCache)); RequestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache)); IsolatedCaches = isolatedCaches ?? throw new ArgumentNullException(nameof(isolatedCaches)); } diff --git a/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs b/src/Umbraco.Core/Cache/DictionaryAppCache.cs similarity index 98% rename from src/Umbraco.Core/Cache/DictionaryCacheProvider.cs rename to src/Umbraco.Core/Cache/DictionaryAppCache.cs index 2ff5f6ea83..4c08bd0524 100644 --- a/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs +++ b/src/Umbraco.Core/Cache/DictionaryAppCache.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Cache /// /// Implements on top of a concurrent dictionary. /// - public class DictionaryCacheProvider : IAppCache + public class DictionaryAppCache : IAppCache { /// /// Gets the internal items dictionary, for tests only! diff --git a/src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs similarity index 99% rename from src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs rename to src/Umbraco.Core/Cache/FastDictionaryAppCache.cs index a3863dac52..bd545694f7 100644 --- a/src/Umbraco.Core/Cache/FastDictionaryCacheProvider.cs +++ b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs @@ -10,7 +10,7 @@ namespace Umbraco.Core.Cache /// /// Implements a fast on top of a concurrent dictionary. /// - internal class FastDictionaryCacheProvider : IAppCache + internal class FastDictionaryAppCache : IAppCache { /// /// Gets the internal items dictionary, for tests only! diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 6bfe9cdb55..8f1fa54a0c 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -332,7 +332,7 @@ namespace Umbraco.Core.Runtime return new AppCaches( new DeepCloneAppCache(new ObjectCacheAppCache()), - new DictionaryCacheProvider(), + new DictionaryAppCache(), NoAppCache.Instance, new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 5b2692359a..49a1cf8d8f 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -121,7 +121,7 @@ - + @@ -141,7 +141,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/AppCacheTests.cs b/src/Umbraco.Tests/Cache/AppCacheTests.cs index f18e08d680..29d61cc14a 100644 --- a/src/Umbraco.Tests/Cache/AppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/AppCacheTests.cs @@ -27,9 +27,9 @@ namespace Umbraco.Tests.Cache [Test] public void Throws_On_Reentry() { - // don't run for StaticCacheProvider - not making sense - if (GetType() == typeof (StaticAppCacheTests)) - Assert.Ignore("Do not run for StaticCacheProvider."); + // don't run for DictionaryAppCache - not making sense + if (GetType() == typeof (DictionaryAppCacheTests)) + Assert.Ignore("Do not run for DictionaryAppCache."); Exception exception = null; var result = AppCache.Get("blah", () => diff --git a/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs index 635155f68e..0be38d2c55 100644 --- a/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs @@ -7,19 +7,19 @@ namespace Umbraco.Tests.Cache [TestFixture] public class HttpRequestAppCacheTests : AppCacheTests { - private HttpRequestAppCache _provider; + private HttpRequestAppCache _appCache; private FakeHttpContextFactory _ctx; public override void Setup() { base.Setup(); _ctx = new FakeHttpContextFactory("http://localhost/test"); - _provider = new HttpRequestAppCache(_ctx.HttpContext); + _appCache = new HttpRequestAppCache(_ctx.HttpContext); } internal override IAppCache AppCache { - get { return _provider; } + get { return _appCache; } } protected override int GetTotalItemCount @@ -29,24 +29,24 @@ namespace Umbraco.Tests.Cache } [TestFixture] - public class StaticAppCacheTests : AppCacheTests + public class DictionaryAppCacheTests : AppCacheTests { - private DictionaryCacheProvider _provider; + private DictionaryAppCache _appCache; public override void Setup() { base.Setup(); - _provider = new DictionaryCacheProvider(); + _appCache = new DictionaryAppCache(); } internal override IAppCache AppCache { - get { return _provider; } + get { return _appCache; } } protected override int GetTotalItemCount { - get { return _provider.Items.Count; } + get { return _appCache.Items.Count; } } } } diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index f740637602..147a159d5f 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Cache.PublishedCache _xml = new XmlDocument(); _xml.LoadXml(GetXml()); var xmlStore = new XmlStore(() => _xml, null, null, null); - var appCache = new DictionaryCacheProvider(); + var appCache = new DictionaryAppCache(); var domainCache = new DomainCache(ServiceContext.DomainService, DefaultCultureAccessor); var publishedShapshot = new Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedSnapshot( new PublishedContentCache(xmlStore, domainCache, appCache, globalSettings, new SiteDomainHelper(), ContentTypesCache, null, null), diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs index ee16a1dede..cfc45b8f53 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs @@ -75,7 +75,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var mChild2 = MakeNewMedia("Child2", mType, user, mRoot2.Id); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var roots = cache.GetAtRoot(); Assert.AreEqual(2, roots.Count()); Assert.IsTrue(roots.Select(x => x.Id).ContainsAll(new[] {mRoot1.Id, mRoot2.Id})); @@ -93,7 +93,7 @@ namespace Umbraco.Tests.Cache.PublishedCache //var publishedMedia = PublishedMediaTests.GetNode(mRoot.Id, GetUmbracoContext("/test", 1234)); var umbracoContext = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var publishedMedia = cache.GetById(mRoot.Id); Assert.IsNotNull(publishedMedia); @@ -204,7 +204,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var result = new SearchResult("1234", 1, () => fields.ToDictionary(x => x.Key, x => new List { x.Value })); - var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var doc = store.CreateFromCacheValues(store.ConvertFromSearchResult(result)); DoAssert(doc, 1234, key, templateIdVal: null, 0, "/media/test.jpg", "Image", 23, "Shannon", "Shannon", 0, 0, "-1,1234", DateTime.Parse("2012-07-17T10:34:09"), DateTime.Parse("2012-07-16T10:34:09"), 2); @@ -220,7 +220,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var xmlDoc = GetMediaXml(); ((XmlElement)xmlDoc.DocumentElement.FirstChild).SetAttribute("key", key.ToString()); var navigator = xmlDoc.SelectSingleNode("/root/Image").CreateNavigator(); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var doc = cache.CreateFromCacheValues(cache.ConvertFromXPathNavigator(navigator, true)); DoAssert(doc, 2000, key, templateIdVal: null, 2, "image1", "Image", 23, "Shannon", "Shannon", 33, 33, "-1,2000", DateTime.Parse("2012-06-12T14:13:17"), DateTime.Parse("2012-07-20T18:50:43"), 1); diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 225bd17618..15549d5d46 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -23,7 +23,7 @@ namespace Umbraco.Tests.Macros //we DO want cache enabled for these tests var cacheHelper = new AppCaches( new ObjectCacheAppCache(), - new DictionaryCacheProvider(), + new DictionaryAppCache(), NoAppCache.Instance, new IsolatedCaches(type => new ObjectCacheAppCache())); //Current.ApplicationContext = new ApplicationContext(cacheHelper, new ProfilingLogger(Mock.Of(), Mock.Of())); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index 1641631f43..9b1c4defa2 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -77,8 +77,8 @@ namespace Umbraco.Tests.Persistence.Repositories { var realCache = new AppCaches( new ObjectCacheAppCache(), - new DictionaryCacheProvider(), - new DictionaryCacheProvider(), + new DictionaryAppCache(), + new DictionaryAppCache(), new IsolatedCaches(t => new ObjectCacheAppCache())); var provider = TestObjects.GetScopeProvider(Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index 33c8524bb4..5635def412 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -48,8 +48,8 @@ namespace Umbraco.Tests.Persistence.Repositories var realCache = new AppCaches( new ObjectCacheAppCache(), - new DictionaryCacheProvider(), - new DictionaryCacheProvider(), + new DictionaryAppCache(), + new DictionaryAppCache(), new IsolatedCaches(t => new ObjectCacheAppCache())); var provider = TestObjects.GetScopeProvider(Logger); diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs index 04444855fb..76fdd81ec2 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs @@ -118,8 +118,8 @@ namespace Umbraco.Tests.Published publishedContentTypeFactory.CreatePropertyType("prop1", 1), }); - var elementsCache = new FastDictionaryCacheProvider(); - var snapshotCache = new FastDictionaryCacheProvider(); + var elementsCache = new FastDictionaryAppCache(); + var snapshotCache = new FastDictionaryAppCache(); var publishedSnapshot = new Mock(); publishedSnapshot.Setup(x => x.SnapshotCache).Returns(snapshotCache); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 4257e3dabb..dfb51e83fb 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -68,7 +68,7 @@ namespace Umbraco.Tests.PublishedContent internal IPublishedContent GetNode(int id, UmbracoContext umbracoContext) { var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), - ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, + ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var doc = cache.GetById(id); Assert.IsNotNull(doc); @@ -126,7 +126,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -156,7 +156,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //ensure it is found var publishedMedia = cache.GetById(3113); @@ -203,7 +203,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -231,7 +231,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -259,7 +259,7 @@ namespace Umbraco.Tests.PublishedContent var searcher = indexer.GetSearcher(); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(1111); @@ -288,7 +288,7 @@ namespace Umbraco.Tests.PublishedContent var ctx = GetUmbracoContext("/test"); var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(3113); @@ -314,7 +314,7 @@ namespace Umbraco.Tests.PublishedContent var ctx = GetUmbracoContext("/test"); var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace var publishedMedia = cache.GetById(3113); @@ -482,7 +482,7 @@ namespace Umbraco.Tests.PublishedContent "); var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var nav = node.CreateNavigator(); @@ -502,7 +502,7 @@ namespace Umbraco.Tests.PublishedContent var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); var nav = errorXml.CreateNavigator(); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryCacheProvider(), ContentTypesCache, Factory.GetInstance()); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); Assert.IsNull(converted); diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index c56ec57db0..99d2fbd222 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -42,7 +42,7 @@ namespace Umbraco.Tests.Scoping // this is what's created core web runtime return new AppCaches( new DeepCloneAppCache(new ObjectCacheAppCache()), - new DictionaryCacheProvider(), + new DictionaryAppCache(), NoAppCache.Instance, new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index bcb1c6ede3..3cca34fe77 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -949,14 +949,15 @@ namespace Umbraco.Web.PublishedCache.NuCache // even though the underlying elements may not change (store snapshots) public PublishedSnapshot.PublishedSnapshotElements GetElements(bool previewDefault) { - // note: using ObjectCacheRuntimeCacheProvider for elements and snapshot caches + // note: using ObjectCacheAppCache for elements and snapshot caches // is not recommended because it creates an inner MemoryCache which is a heavy - // thing - better use a StaticCacheProvider which "just" creates a concurrent + // thing - better use a dictionary-based cache which "just" creates a concurrent // dictionary - // for snapshot cache, StaticCacheProvider MAY be OK but it is not thread-safe, + // for snapshot cache, DictionaryAppCache MAY be OK but it is not thread-safe, // nothing like that... - // for elements cache, StaticCacheProvider is a No-No, use something better. + // for elements cache, DictionaryAppCache is a No-No, use something better. + // ie FastDictionaryAppCache (thread safe and all) ContentStore.Snapshot contentSnap, mediaSnap; SnapDictionary.Snapshot domainSnap; @@ -998,11 +999,11 @@ namespace Umbraco.Web.PublishedCache.NuCache _contentGen = contentSnap.Gen; _mediaGen = mediaSnap.Gen; _domainGen = domainSnap.Gen; - elementsCache = _elementsCache = new FastDictionaryCacheProvider(); + elementsCache = _elementsCache = new FastDictionaryAppCache(); } } - var snapshotCache = new DictionaryCacheProvider(); + var snapshotCache = new DictionaryAppCache(); var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _publishedContentTypeFactory, _logger); diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs index a622a4934c..816eb3c545 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs @@ -17,9 +17,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly XmlStore _xmlStore; private readonly PublishedContentTypeCache _contentTypeCache; - public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCacheProvider, IMemberService memberService, PublishedContentTypeCache contentTypeCache) + public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache) { - _requestCache = requestCacheProvider; + _requestCache = requestCache; _memberService = memberService; _xmlStore = xmlStore; _contentTypeCache = contentTypeCache; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index eb54c85984..2e19fc423b 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -421,13 +421,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// /// The Xml node. /// A value indicating whether we are previewing or not. - /// A cache provider. + /// A cache. /// A content type cache. /// The IPublishedContent corresponding to the Xml cache node. /// Maintains a per-request cache of IPublishedContent items in order to make /// sure that we create only one instance of each for the duration of a request. The /// returned IPublishedContent is a model, if models are enabled. - public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache cacheProvider, PublishedContentTypeCache contentTypeCache) + public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache appCache, PublishedContentTypeCache contentTypeCache) { // only 1 per request @@ -435,7 +435,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var id = attrs?.GetNamedItem("id").Value; if (id.IsNullOrWhiteSpace()) throw new InvalidOperationException("Node has no ID attribute."); var key = CacheKeyPrefix + id; // dont bother with preview, wont change during request in Xml cache - return (IPublishedContent) cacheProvider.Get(key, () => (new XmlPublishedContent(node, isPreviewing, cacheProvider, contentTypeCache)).CreateModel()); + return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache)).CreateModel()); } public static void ClearRequest() diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Web/Runtime/WebRuntime.cs index e9d27a2a1c..90da402849 100644 --- a/src/Umbraco.Web/Runtime/WebRuntime.cs +++ b/src/Umbraco.Web/Runtime/WebRuntime.cs @@ -63,7 +63,7 @@ namespace Umbraco.Web.Runtime // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache)), - new DictionaryCacheProvider(), + new DictionaryAppCache(), // we need request based cache when running in web-based context new HttpRequestAppCache(), new IsolatedCaches(type => From a83ac4a24dd6ced3c6f993cd6c4e9c048191df67 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Fri, 18 Jan 2019 09:31:38 +0100 Subject: [PATCH 196/223] #3417 retreive data for edit screen --- .../src/common/resources/macro.resource.js | 6 + .../macros/infiniteeditors/parameter.html | 2 +- .../views/macros/macros.edit.controller.js | 48 ++++---- .../src/views/macros/views/settings.html | 3 +- src/Umbraco.Web/Editors/MacrosController.cs | 116 ++++++++++++++---- .../Models/ContentEditing/MacroDisplay.cs | 67 ++++++++++ .../ContentEditing/MacroParameterDisplay.cs | 29 +++++ src/Umbraco.Web/Umbraco.Web.csproj | 2 + 8 files changed, 220 insertions(+), 53 deletions(-) create mode 100644 src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs create mode 100644 src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index 5313eadcaa..1471abd8d3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -101,6 +101,12 @@ function macroResource($q, $http, umbRequestHelper) { $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetParameterEditors"), "Failed to get parameter editors") ); + }, + + getById: function(id) { + return umbRequestHelper.resourcePromise( + $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetById", { "id" : id}), "Failed to get macro") + ); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html index bf9dbf86a3..402c3c4984 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html @@ -26,7 +26,7 @@ - + diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js index f8cde110e6..91af9b0f09 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js @@ -83,11 +83,24 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta return deferred.promise; } + function getMacro() { + var deferred = $q.defer(); + + macroResource.getById($routeParams.id).then(function (data) { + deferred.resolve(data); + }, function () { + deferred.reject(); + }); + + return deferred.promise; + } + function init() { vm.page.loading = true; vm.promises['partialViews'] = getPartialViews(); vm.promises['parameterEditors'] = getParameterEditors(); + vm.promises['macro'] = getMacro(); $q.all(vm.promises).then(function (values) { var keys = Object.keys(values); @@ -102,12 +115,20 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta if (keys[i] === 'parameterEditors') { vm.parameterEditors = values[key]; } + + if (keys[i] === 'macro') { + vm.macro = values[key]; + editorState.set(vm.macro); + + navigationService.syncTree({ tree: "macros", path: vm.macro.path, forceReload: true }).then(function (syncArgs) { + vm.page.menu.currentNode = syncArgs.node; + }); + } } vm.page.loading = false; }); - vm.page.navigation = [ { "name": "Settings", @@ -123,31 +144,6 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta "view": "views/macros/views/parameters.html" } ]; - - vm.macro = { - "name": "Test macro", - "alias": "testMacro", - "id": 1, - "key": "unique key goes here", - "useInEditor": true, - "renderInEditor": false, - "cachePeriod": 2400, - "cacheByPage": true, - "cacheByUser": false, - "view": "Second", - "parameters": [ - { - "key": "title", - "label": "Label", - "editor": "editor" - }, - { - "key": "link", - "label": "Link", - "editor": "Link picker" - } - ] - } } init(); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html index 51e83a9134..ba5b324837 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -2,7 +2,8 @@ - + diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 6e2d032ad4..d604137e19 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -1,25 +1,24 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Web.Http; - -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; - -using Constants = Umbraco.Core.Constants; - -namespace Umbraco.Web.Editors +namespace Umbraco.Web.Editors { + using System; using System.Collections.Generic; using System.IO; using System.Linq; + using System.Net; + using System.Net.Http; + using System.Web.Http; + using Umbraco.Core; using Umbraco.Core.IO; + using Umbraco.Core.Logging; + using Umbraco.Core.Models; using Umbraco.Web.Composing; + using Umbraco.Web.Models.ContentEditing; + using Umbraco.Web.Mvc; + using Umbraco.Web.WebApi; + using Umbraco.Web.WebApi.Filters; + + using Constants = Umbraco.Core.Constants; /// /// The API controller used for editing dictionary items @@ -41,33 +40,75 @@ namespace Umbraco.Web.Editors public HttpResponseMessage Create(string name) { if (string.IsNullOrWhiteSpace(name)) - return Request - .CreateNotificationValidationErrorResponse("Name can not be empty;"); + { + return this.ReturnErrorResponse("Name can not be empty"); + } var alias = name.ToSafeAlias(); - var existingMacro = this.Services.MacroService.GetByAlias(alias); - - if (existingMacro != null) + if (this.Services.MacroService.GetByAlias(alias) != null) { - return Request.CreateNotificationValidationErrorResponse("Macro with this name already exists"); + return this.ReturnErrorResponse("Macro with this name already exists"); } try { - var macro = new Macro { Alias = alias, Name = name, MacroSource = string.Empty }; + var macro = new Macro + { + Alias = alias, + Name = name, + MacroSource = string.Empty, + MacroType = MacroTypes.PartialView + }; this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); - return Request.CreateResponse(HttpStatusCode.OK, macro.Id); + return this.Request.CreateResponse(HttpStatusCode.OK, macro.Id); } catch (Exception exception) { - this.Logger.Error(exception, "Error creating macro"); - return Request.CreateNotificationValidationErrorResponse("Error creating dictionary item"); + return this.ReturnErrorResponse("Error creating macro", true, exception); } } + [HttpGet] + public HttpResponseMessage GetById(int id) + { + var macro = this.Services.MacroService.GetById(id); + + if (macro == null) + { + return this.ReturnErrorResponse($"Macro with id {id} does not exist"); + } + + var macroDisplay = new MacroDisplay + { + Alias = macro.Alias, Id = macro.Id, Key = macro.Key, Name = macro.Name, + CacheByPage = macro.CacheByPage, CacheByUser = macro.CacheByMember, + CachePeriod = macro.CacheDuration, + View = macro.MacroSource, + RenderInEditor = !macro.DontRender, + UseInEditor = macro.UseInEditor, + Path = $"-1,{macro.Id}" + }; + + var parameters = new List(); + + foreach (var param in macro.Properties.Values.OrderBy(x => x.SortOrder)) + { + parameters.Add(new MacroParameterDisplay + { + Editor = param.EditorAlias, + Key = param.Alias, + Label = param.Name + }); + } + + macroDisplay.Parameters = parameters; + + return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); + } + /// /// Gets a list of available macro partials /// @@ -94,6 +135,31 @@ namespace Umbraco.Web.Editors return this.Request.CreateResponse(HttpStatusCode.OK, Current.ParameterEditors); } + /// + /// Returns a error response and optionally logs it + /// + /// + /// The error message. + /// + /// + /// Value to indicate if the error needs to be logged + /// + /// + /// The exception to log + /// + /// + /// The . + /// + private HttpResponseMessage ReturnErrorResponse(string message, bool logError = false, Exception exception = null) + { + if (logError && exception != null) + { + this.Logger.Error(exception, message); + } + + return this.Request.CreateNotificationValidationErrorResponse(message); + } + /// /// Finds all the macro partials /// diff --git a/src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs new file mode 100644 index 0000000000..e84887b88b --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Umbraco.Web.Models.ContentEditing +{ + /// + /// The macro display model + /// + [DataContract(Name = "dictionary", Namespace = "")] + public class MacroDisplay : EntityBasic, INotificationModel + { + /// + /// Initializes a new instance of the class. + /// + public MacroDisplay() + { + this.Notifications = new List(); + this.Parameters = new List(); + } + + /// + [DataMember(Name = "notifications")] + public List Notifications { get; } + + /// + /// Gets or sets a value indicating whether the macro can be used in a rich text editor. + /// + [DataMember(Name = "useInEditor")] + public bool UseInEditor { get; set; } + + /// + /// Gets or sets a value indicating whether the macro should be rendered a rich text editor. + /// + [DataMember(Name = "renderInEditor")] + public bool RenderInEditor { get; set; } + + /// + /// Gets or sets the cache period. + /// + [DataMember(Name = "cachePeriod")] + public int CachePeriod { get; set; } + + /// + /// Gets or sets a value indicating whether the macro should be cached by page + /// + [DataMember(Name = "cacheByPage")] + public bool CacheByPage { get; set; } + + /// + /// Gets or sets a value indicating whether the macro should be cached by user + /// + [DataMember(Name = "cacheByUser")] + public bool CacheByUser { get; set; } + + /// + /// Gets or sets the view. + /// + [DataMember(Name = "view")] + public string View { get; set; } + + /// + /// Gets or sets the parameters. + /// + [DataMember(Name = "parameters")] + public IEnumerable Parameters { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs new file mode 100644 index 0000000000..56d3d1b76e --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs @@ -0,0 +1,29 @@ +namespace Umbraco.Web.Models.ContentEditing +{ + using System.Runtime.Serialization; + + /// + /// The macro parameter display. + /// + [DataContract(Name = "parameter", Namespace = "")] + public class MacroParameterDisplay + { + /// + /// Gets or sets the key. + /// + [DataMember(Name = "key")] + public string Key { get; set; } + + /// + /// Gets or sets the label. + /// + [DataMember(Name = "label")] + public string Label { get; set; } + + /// + /// Gets or sets the editor. + /// + [DataMember(Name = "editor")] + public string Editor { get; set; } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 7186835ba8..dbf422531d 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -158,6 +158,8 @@ + + From 6dd4d7f475b72ced50578f9a16e2e99d5c4ce7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 18 Jan 2019 10:12:24 +0100 Subject: [PATCH 197/223] V8 FE Gulp Fastdev script --- .editorconfig | 6 +- .../gulp/tasks/fastdev.js | 13 ++ .../gulp/util/processJs.js | 24 ++- .../gulp/util/processLess.js | 21 ++- src/Umbraco.Web.UI.Client/gulpfile.js | 2 + src/Umbraco.Web.UI.Client/package-lock.json | 154 +++++++++++++++--- src/Umbraco.Web.UI.Client/package.json | 5 +- 7 files changed, 185 insertions(+), 40 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/gulp/tasks/fastdev.js diff --git a/.editorconfig b/.editorconfig index c63ef39430..2305dd4b32 100644 --- a/.editorconfig +++ b/.editorconfig @@ -34,4 +34,8 @@ dotnet_naming_style.prefix_underscore.required_prefix = _ csharp_style_var_for_built_in_types = true:suggestion csharp_style_var_when_type_is_apparent = true:suggestion csharp_style_var_elsewhere = true:suggestion -csharp_prefer_braces = false : none +csharp_prefer_braces = false : none + +[*.{js,less}] +trim_trailing_whitespace = false +insert_final_newline = false diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/fastdev.js b/src/Umbraco.Web.UI.Client/gulp/tasks/fastdev.js new file mode 100644 index 0000000000..888ed38fec --- /dev/null +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/fastdev.js @@ -0,0 +1,13 @@ +'use strict'; + +var config = require('../config'); +var gulp = require('gulp'); +var runSequence = require('run-sequence'); + +// Dev - build the files ready for development and start watchers +gulp.task('fastdev', function(cb) { + + global.isProd = false; + + runSequence(["dependencies", "js", "less", "views"], "watch", cb); +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/gulp/util/processJs.js b/src/Umbraco.Web.UI.Client/gulp/util/processJs.js index c110fa9cae..45927dc0e6 100644 --- a/src/Umbraco.Web.UI.Client/gulp/util/processJs.js +++ b/src/Umbraco.Web.UI.Client/gulp/util/processJs.js @@ -9,18 +9,24 @@ var concat = require('gulp-concat'); var wrap = require("gulp-wrap-js"); module.exports = function(files, out) { - - return gulp.src(files) + + var task = gulp.src(files); + + if (global.isProd === true) { // check for js errors - .pipe(eslint()) + task = task.pipe(eslint()); // outputs the lint results to the console - .pipe(eslint.format()) - // sort files in stream by path or any custom sort comparator - .pipe(babel()) + task = task.pipe(eslint.format()); + } + + // sort files in stream by path or any custom sort comparator + task = task.pipe(babel()) .pipe(sort()) .pipe(concat(out)) .pipe(wrap('(function(){\n%= body %\n})();')) .pipe(gulp.dest(config.root + config.targets.js)); - - console.log(out + " compiled"); -}; + + + return task; + +}; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/gulp/util/processLess.js b/src/Umbraco.Web.UI.Client/gulp/util/processLess.js index e2bb758499..26f69865d9 100644 --- a/src/Umbraco.Web.UI.Client/gulp/util/processLess.js +++ b/src/Umbraco.Web.UI.Client/gulp/util/processLess.js @@ -10,17 +10,24 @@ var cleanCss = require("gulp-clean-css"); var rename = require('gulp-rename'); module.exports = function(files, out) { + var processors = [ autoprefixer, cssnano({zindex: false}) ]; - return gulp.src(files) - .pipe(less()) - .pipe(cleanCss()) - .pipe(postcss(processors)) + var task = gulp.src(files) + .pipe(less()); + + + if (global.isProd === true) { + task = task.pipe(cleanCss()); + } + + task = task.pipe(postcss(processors)) .pipe(rename(out)) .pipe(gulp.dest(config.root + config.targets.css)); - - console.log(out + " compiled"); -} + + return task; + +}; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/gulpfile.js b/src/Umbraco.Web.UI.Client/gulpfile.js index f01d992013..79a9d04156 100755 --- a/src/Umbraco.Web.UI.Client/gulpfile.js +++ b/src/Umbraco.Web.UI.Client/gulpfile.js @@ -11,4 +11,6 @@ * To add a new task, simply add a new task file to gulp/tasks. */ +global.isProd = true; + require('./gulp'); diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 02ad091f75..fe657ae470 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -5115,6 +5115,12 @@ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "fs": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz", + "integrity": "sha1-4fJE7zkzwbKmS9R5kTYGDQ9ZFPg=", + "dev": true + }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -5204,14 +5210,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5226,20 +5230,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5356,8 +5357,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5369,7 +5369,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5384,7 +5383,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5392,14 +5390,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5418,7 +5414,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5499,8 +5494,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5512,7 +5506,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5634,7 +5627,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6133,6 +6125,12 @@ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", "dev": true }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, "gulp": { "version": "3.9.1", "resolved": "http://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", @@ -6930,6 +6928,102 @@ } } }, + "gulp-notify": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz", + "integrity": "sha512-qEocs1UVoDKKUjfsxJNMNwkRla0PbsyJwsqNNXpzYWsLQ29LhxRMY3wnTGZcc4hMHtalnvah/Dwlwb4NijH/0A==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "fancy-log": "^1.3.2", + "lodash.template": "^4.4.0", + "node-notifier": "^5.2.1", + "node.extend": "^2.0.0", + "plugin-error": "^0.1.2", + "through2": "^2.0.3" + }, + "dependencies": { + "arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + } + }, + "arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "requires": { + "kind-of": "^1.1.0" + } + }, + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true + }, + "lodash.template": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", + "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", + "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0" + } + }, + "node.extend": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", + "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", + "dev": true, + "requires": { + "has": "^1.0.3", + "is": "^3.2.1" + } + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + } + } + } + }, "gulp-open": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/gulp-open/-/gulp-open-3.0.1.tgz", @@ -9382,6 +9476,18 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-notifier": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz", + "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, "node-releases": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.5.tgz", @@ -14138,6 +14244,12 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 6e8159a940..61bdb88f17 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -3,8 +3,9 @@ "scripts": { "test": "karma start test/config/karma.conf.js --singlerun", "build": "gulp build", - "dev": "gulp dev", - "docs": "gulp docs" + "dev": "gulp dev", + "fastdev": "gulp fastdev", + "docs": "gulp docs" }, "dependencies": { "ace-builds": "1.4.2", From cee1171d39a93de59f862a2a7107edae3a93602f Mon Sep 17 00:00:00 2001 From: Callum Whyte Date: Fri, 18 Jan 2019 20:53:38 +1100 Subject: [PATCH 198/223] Removing masterpages support from V8 (#3971) --- .../Composers/ConfigurationComposer.cs | 1 - .../UmbracoSettings/ITemplatesSection.cs | 9 - .../IUmbracoSettingsSection.cs | 4 - .../UmbracoSettings/TemplatesElement.cs | 20 - .../UmbracoSettings/UmbracoSettingsSection.cs | 18 +- src/Umbraco.Core/IO/FileSystems.cs | 14 - src/Umbraco.Core/IO/IFileSystems.cs | 5 - src/Umbraco.Core/IO/MasterPageHelper.cs | 445 ------------------ src/Umbraco.Core/IO/SystemDirectories.cs | 4 - src/Umbraco.Core/Models/ITemplate.cs | 6 +- .../Packaging/PackageDataInstallation.cs | 17 +- .../Repositories/ITemplateRepository.cs | 19 +- .../Implement/TemplateRepository.cs | 136 +----- src/Umbraco.Core/Services/IFileService.cs | 15 - .../Services/Implement/FileService.cs | 24 +- src/Umbraco.Core/Umbraco.Core.csproj | 3 - .../TemplateElementDefaultTests.cs | 13 - .../UmbracoSettings/TemplateElementTests.cs | 16 - .../UmbracoSettings/umbracoSettings.config | 4 - .../umbracoSettings.minimal.config | 5 - src/Umbraco.Tests/IO/IoHelperTests.cs | 1 - .../Repositories/ContentTypeRepositoryTest.cs | 9 +- .../Repositories/DocumentRepositoryTest.cs | 2 +- .../Repositories/DomainRepositoryTest.cs | 4 +- .../PublicAccessRepositoryTest.cs | 4 +- .../Repositories/TagRepositoryTest.cs | 2 +- .../Repositories/TemplateRepositoryTest.cs | 135 +----- .../Repositories/UserRepositoryTest.cs | 2 +- .../Services/ContentServicePerformanceTest.cs | 8 +- .../Services/ContentServiceTests.cs | 2 +- .../Templates/MasterPageHelperTests.cs | 21 - .../Templates/TemplateRepositoryTests.cs | 121 ----- .../TestHelpers/SettingsForTests.cs | 3 - src/Umbraco.Tests/TestHelpers/TestHelper.cs | 5 +- .../TestHelpers/TestObjects-Mocks.cs | 3 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 - src/Umbraco.Tests/Umbraco.Tests.csproj | 4 - .../config/umbracoSettings.Release.config | 5 - .../config/umbracoSettings.config | 5 - .../FolderAndFilePermissionsCheck.cs | 1 - .../Install/FilePermissionHelper.cs | 3 +- src/Umbraco.Web/Routing/PublishedRouter.cs | 4 - .../Trees/TemplatesTreeController.cs | 13 +- .../umbraco.presentation/default.aspx.cs | 16 - 44 files changed, 38 insertions(+), 1114 deletions(-) delete mode 100644 src/Umbraco.Core/Configuration/UmbracoSettings/ITemplatesSection.cs delete mode 100644 src/Umbraco.Core/Configuration/UmbracoSettings/TemplatesElement.cs delete mode 100644 src/Umbraco.Core/IO/MasterPageHelper.cs delete mode 100644 src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementDefaultTests.cs delete mode 100644 src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementTests.cs delete mode 100644 src/Umbraco.Tests/Templates/MasterPageHelperTests.cs delete mode 100644 src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs diff --git a/src/Umbraco.Core/Composing/Composers/ConfigurationComposer.cs b/src/Umbraco.Core/Composing/Composers/ConfigurationComposer.cs index ca86f623cc..7fba47a2cd 100644 --- a/src/Umbraco.Core/Composing/Composers/ConfigurationComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ConfigurationComposer.cs @@ -15,7 +15,6 @@ namespace Umbraco.Core.Composing.Composers // register others composition.RegisterUnique(factory => factory.GetInstance().Content); - composition.RegisterUnique(factory => factory.GetInstance().Templates); composition.RegisterUnique(factory => factory.GetInstance().RequestHandler); composition.RegisterUnique(factory => factory.GetInstance().Security); diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ITemplatesSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ITemplatesSection.cs deleted file mode 100644 index 67fd58030b..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ITemplatesSection.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface ITemplatesSection : IUmbracoConfigurationSection - { - RenderingEngine DefaultRenderingEngine { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs index 28da03ff2d..33416d38cc 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; namespace Umbraco.Core.Configuration.UmbracoSettings { @@ -12,8 +11,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings ISecuritySection Security { get; } IRequestHandlerSection RequestHandler { get; } - - ITemplatesSection Templates { get; } ILoggingSection Logging { get; } @@ -22,6 +19,5 @@ namespace Umbraco.Core.Configuration.UmbracoSettings IProvidersSection Providers { get; } IWebRoutingSection WebRouting { get; } - } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/TemplatesElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/TemplatesElement.cs deleted file mode 100644 index 8c929b02d8..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/TemplatesElement.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class TemplatesElement : UmbracoConfigurationElement, ITemplatesSection - { - [ConfigurationProperty("defaultRenderingEngine", IsRequired = true)] - internal InnerTextConfigurationElement DefaultRenderingEngine - { - get { return GetOptionalTextElement("defaultRenderingEngine", RenderingEngine.Mvc); } - } - - RenderingEngine ITemplatesSection.DefaultRenderingEngine - { - get { return DefaultRenderingEngine; } - } - - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/UmbracoSettingsSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/UmbracoSettingsSection.cs index d36410f317..9ed635f6a9 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/UmbracoSettingsSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/UmbracoSettingsSection.cs @@ -1,11 +1,7 @@ -using System; -using System.ComponentModel; -using System.Configuration; -using System.Linq; +using System.Configuration; namespace Umbraco.Core.Configuration.UmbracoSettings { - public class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection { [ConfigurationProperty("backOffice")] @@ -32,12 +28,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings get { return (RequestHandlerElement)this["requestHandler"]; } } - [ConfigurationProperty("templates")] - internal TemplatesElement Templates - { - get { return (TemplatesElement)this["templates"]; } - } - [ConfigurationProperty("logging")] internal LoggingElement Logging { @@ -77,11 +67,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings get { return RequestHandler; } } - ITemplatesSection IUmbracoSettingsSection.Templates - { - get { return Templates; } - } - IBackOfficeSection IUmbracoSettingsSection.BackOffice { get { return BackOffice; } @@ -106,6 +91,5 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { get { return WebRouting; } } - } } diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index 7fc846319b..63a1259acb 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -19,7 +19,6 @@ namespace Umbraco.Core.IO private ShadowWrapper _partialViewsFileSystem; private ShadowWrapper _stylesheetsFileSystem; private ShadowWrapper _scriptsFileSystem; - private ShadowWrapper _masterPagesFileSystem; private ShadowWrapper _mvcViewsFileSystem; // well-known file systems lazy initialization @@ -102,16 +101,6 @@ namespace Umbraco.Core.IO } } - /// - public IFileSystem MasterPagesFileSystem - { - get - { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); - return _masterPagesFileSystem; - } - } - /// public IFileSystem MvcViewsFileSystem { @@ -135,14 +124,12 @@ namespace Umbraco.Core.IO var partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews); var stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css); var scriptsFileSystem = new PhysicalFileSystem(SystemDirectories.Scripts); - var masterPagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages); var mvcViewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews); _macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", IsScoped); _partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", IsScoped); _stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", IsScoped); _scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", IsScoped); - _masterPagesFileSystem = new ShadowWrapper(masterPagesFileSystem, "masterpages", IsScoped); _mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "Views", IsScoped); // fixme locking? @@ -150,7 +137,6 @@ namespace Umbraco.Core.IO _shadowWrappers.Add(_partialViewsFileSystem); _shadowWrappers.Add(_stylesheetsFileSystem); _shadowWrappers.Add(_scriptsFileSystem); - _shadowWrappers.Add(_masterPagesFileSystem); _shadowWrappers.Add(_mvcViewsFileSystem); return null; diff --git a/src/Umbraco.Core/IO/IFileSystems.cs b/src/Umbraco.Core/IO/IFileSystems.cs index d74ad48145..f7d35058e3 100644 --- a/src/Umbraco.Core/IO/IFileSystems.cs +++ b/src/Umbraco.Core/IO/IFileSystems.cs @@ -25,11 +25,6 @@ /// IFileSystem ScriptsFileSystem { get; } - /// - /// Gets the masterpages filesystem. - /// - IFileSystem MasterPagesFileSystem { get; } - /// /// Gets the MVC views filesystem. /// diff --git a/src/Umbraco.Core/IO/MasterPageHelper.cs b/src/Umbraco.Core/IO/MasterPageHelper.cs deleted file mode 100644 index 049db04b9a..0000000000 --- a/src/Umbraco.Core/IO/MasterPageHelper.cs +++ /dev/null @@ -1,445 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Repositories; -using Umbraco.Core.Services; -using Umbraco.Core.Xml; - -namespace Umbraco.Core.IO -{ - internal class MasterPageHelper - { - private readonly IFileSystem _masterPageFileSystem; - internal static readonly string DefaultMasterTemplate = SystemDirectories.Umbraco + "/masterpages/default.master"; - //private static readonly char[] NewLineChars = Environment.NewLine.ToCharArray(); - - public MasterPageHelper(IFileSystem masterPageFileSystem) - { - if (masterPageFileSystem == null) throw new ArgumentNullException("masterPageFileSystem"); - _masterPageFileSystem = masterPageFileSystem; - } - - public bool MasterPageExists(ITemplate t) - { - return _masterPageFileSystem.FileExists(GetFilePath(t)); - } - - private string GetFilePath(ITemplate t) - { - return GetFilePath(t.Alias); - } - - private string GetFilePath(string alias) - { - return alias + ".master"; - } - - public string CreateMasterPage(ITemplate t, ITemplateRepository templateRepo, bool overWrite = false) - { - string masterpageContent = ""; - - var filePath = GetFilePath(t); - if (_masterPageFileSystem.FileExists(filePath) == false || overWrite) - { - masterpageContent = t.Content.IsNullOrWhiteSpace() ? CreateDefaultMasterPageContent(t, templateRepo) : t.Content; - - var data = Encoding.UTF8.GetBytes(masterpageContent); - var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray(); - - using (var ms = new MemoryStream(withBom)) - { - _masterPageFileSystem.AddFile(filePath, ms, true); - } - } - else - { - using (var s = _masterPageFileSystem.OpenFile(filePath)) - using (var tr = new StreamReader(s, Encoding.UTF8)) - { - masterpageContent = tr.ReadToEnd(); - tr.Close(); - } - } - - return masterpageContent; - } - - //internal string GetFileContents(ITemplate t) - //{ - // var masterpageContent = ""; - // if (_masterPageFileSystem.FileExists(GetFilePath(t))) - // { - // using (var s = _masterPageFileSystem.OpenFile(GetFilePath(t))) - // using (var tr = new StreamReader(s)) - // { - // masterpageContent = tr.ReadToEnd(); - // tr.Close(); - // } - // } - - // return masterpageContent; - //} - - public string UpdateMasterPageFile(ITemplate t, string currentAlias, ITemplateRepository templateRepo) - { - var template = UpdateMasterPageContent(t, currentAlias); - UpdateChildTemplates(t, currentAlias, templateRepo); - var filePath = GetFilePath(t); - - var data = Encoding.UTF8.GetBytes(template); - var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray(); - - using (var ms = new MemoryStream(withBom)) - { - _masterPageFileSystem.AddFile(filePath, ms, true); - } - return template; - } - - private string CreateDefaultMasterPageContent(ITemplate template, ITemplateRepository templateRepo) - { - var design = new StringBuilder(); - design.Append(GetMasterPageHeader(template) + Environment.NewLine); - - if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false) - { - var master = templateRepo.Get(template.MasterTemplateAlias); - if (master != null) - { - foreach (var cpId in GetContentPlaceholderIds(master)) - { - design.Append("" + - Environment.NewLine + - Environment.NewLine + - "" + - Environment.NewLine + - Environment.NewLine); - } - - return design.ToString(); - } - } - - design.Append(GetMasterContentElement(template) + Environment.NewLine); - design.Append(template.Content + Environment.NewLine); - design.Append("" + Environment.NewLine); - - return design.ToString(); - } - - public static IEnumerable GetContentPlaceholderIds(ITemplate template) - { - var retVal = new List(); - - var mp = template.Content; - var path = ""; - var r = new Regex(path, RegexOptions.IgnoreCase); - var m = r.Match(mp); - - while (m.Success) - { - var cc = m.Groups[3].Captures; - retVal.AddRange(cc.Cast().Where(c => c.Value != "server").Select(c => c.Value)); - - m = m.NextMatch(); - } - - return retVal; - } - - private static string UpdateMasterPageContent(ITemplate template, string currentAlias) - { - var masterPageContent = template.Content; - - if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias) - { - var masterHeader = - masterPageContent.Substring(0, masterPageContent.IndexOf("%>", StringComparison.Ordinal) + 2).Trim( - Environment.NewLine.ToCharArray()); - - // find the masterpagefile attribute - var m = Regex.Matches(masterHeader, "(?\\S*)=\"(?[^\"]*)\"", - RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - - foreach (Match attributeSet in m) - { - if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile") - { - // validate the masterpagefile - var currentMasterPageFile = attributeSet.Groups["attributeValue"].Value; - var currentMasterTemplateFile = ParentTemplatePath(template); - - if (currentMasterPageFile != currentMasterTemplateFile) - { - masterPageContent = - masterPageContent.Replace( - attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"", - attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile + - "\""); - } - } - } - } - - return masterPageContent; - } - - private void UpdateChildTemplates(ITemplate template, string currentAlias, ITemplateRepository templateRepo) - { - //if we have a Old Alias if the alias and therefor the masterpage file name has changed... - //so before we save the new masterfile, we'll clear the old one, so we don't up with - //Unused masterpage files - if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias) - { - //Ensure that child templates have the right master masterpage file name - if (template.IsMasterTemplate) - { - var children = templateRepo.GetChildren(template.Id); - foreach (var t in children) - UpdateMasterPageFile(t, null, templateRepo); - } - } - } - - - //private void SaveDesignToFile(ITemplate t, string currentAlias, string design) - //{ - // //kill the old file.. - // if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != t.Alias) - // { - // var oldFile = - // IOHelper.MapPath(SystemDirectories.Masterpages + "/" + currentAlias.Replace(" ", "") + ".master"); - // if (System.IO.File.Exists(oldFile)) - // System.IO.File.Delete(oldFile); - // } - - // // save the file in UTF-8 - // System.IO.File.WriteAllText(GetFilePath(t), design, Encoding.UTF8); - //} - - //internal static void RemoveMasterPageFile(string alias) - //{ - // if (string.IsNullOrWhiteSpace(alias) == false) - // { - // string file = IOHelper.MapPath(SystemDirectories.Masterpages + "/" + alias.Replace(" ", "") + ".master"); - // if (System.IO.File.Exists(file)) - // System.IO.File.Delete(file); - // } - //} - - //internal string SaveTemplateToFile(ITemplate template, string currentAlias, ITemplateRepository templateRepo) - //{ - // var masterPageContent = template.Content; - // if (IsMasterPageSyntax(masterPageContent) == false) - // masterPageContent = ConvertToMasterPageSyntax(template); - - // // Add header to master page if it doesn't exist - // if (masterPageContent.TrimStart().StartsWith("<%@") == false) - // { - // masterPageContent = GetMasterPageHeader(template) + Environment.NewLine + masterPageContent; - // } - // else - // { - // // verify that the masterpage attribute is the same as the masterpage - // var masterHeader = - // masterPageContent.Substring(0, masterPageContent.IndexOf("%>", StringComparison.Ordinal) + 2).Trim(NewLineChars); - - // // find the masterpagefile attribute - // var m = Regex.Matches(masterHeader, "(?\\S*)=\"(?[^\"]*)\"", - // RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - - // foreach (Match attributeSet in m) - // { - // if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile") - // { - // // validate the masterpagefile - // var currentMasterPageFile = attributeSet.Groups["attributeValue"].Value; - // var currentMasterTemplateFile = ParentTemplatePath(template); - - // if (currentMasterPageFile != currentMasterTemplateFile) - // { - // masterPageContent = - // masterPageContent.Replace( - // attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"", - // attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile + - // "\""); - - // } - // } - // } - - // } - - // //we have a Old Alias if the alias and therefor the masterpage file name has changed... - // //so before we save the new masterfile, we'll clear the old one, so we don't up with - // //Unused masterpage files - // if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias) - // { - - // //Ensure that child templates have the right master masterpage file name - // if (template.IsMasterTemplate) - // { - // var children = templateRepo.GetChildren(template.Id); - - // foreach (var t in children) - // UpdateMasterPageFile(t, null, templateRepo); - // } - - // //then kill the old file.. - // var oldFile = GetFilePath(currentAlias); - // if (_masterPageFileSystem.FileExists(oldFile)) - // _masterPageFileSystem.DeleteFile(oldFile); - // } - - // // save the file in UTF-8 - // System.IO.File.WriteAllText(GetFilePath(template), masterPageContent, Encoding.UTF8); - - // return masterPageContent; - //} - - //internal static string ConvertToMasterPageSyntax(ITemplate template) - //{ - // string masterPageContent = GetMasterContentElement(template) + Environment.NewLine; - - // masterPageContent += template.Content; - - // // Parse the design for getitems - // masterPageContent = EnsureMasterPageSyntax(template.Alias, masterPageContent); - - // // append ending asp:content element - // masterPageContent += Environment.NewLine + "" + Environment.NewLine; - - // return masterPageContent; - //} - - public static bool IsMasterPageSyntax(string code) - { - return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || - code.InvariantContains("", ParentTemplatePath(template)) + Environment.NewLine; - } - - private static string ParentTemplatePath(ITemplate template) - { - var masterTemplate = DefaultMasterTemplate; - if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false) - masterTemplate = SystemDirectories.Masterpages + "/" + template.MasterTemplateAlias + ".master"; - - return masterTemplate; - } - - internal static string GetMasterContentElement(ITemplate template) - { - if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false) - { - string masterAlias = template.MasterTemplateAlias; - return - String.Format("", masterAlias); - } - else - return - String.Format(""); - - } - - internal static string EnsureMasterPageSyntax(string templateAlias, string masterPageContent) - { - ReplaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", true); - ReplaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", false); - - // Parse the design for macros - ReplaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", true); - ReplaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", false); - - // Parse the design for load childs - masterPageContent = masterPageContent.Replace("", CreateDefaultPlaceHolder(templateAlias)) - .Replace("", CreateDefaultPlaceHolder(templateAlias)); - // Parse the design for aspnet forms - GetAspNetMasterPageForm(ref masterPageContent, templateAlias); - masterPageContent = masterPageContent.Replace("", ""); - // Parse the design for aspnet heads - masterPageContent = masterPageContent.Replace("", String.Format("", templateAlias.Replace(" ", ""))); - masterPageContent = masterPageContent.Replace("", ""); - return masterPageContent; - } - - - private static void GetAspNetMasterPageForm(ref string design, string templateAlias) - { - var formElement = Regex.Match(design, GetElementRegExp("?ASPNET_FORM", false), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - - if (string.IsNullOrEmpty(formElement.Value) == false) - { - string formReplace = String.Format("
", templateAlias.Replace(" ", "")); - if (formElement.Groups.Count == 0) - { - formReplace += ""; - } - design = design.Replace(formElement.Value, formReplace); - } - } - - private static string CreateDefaultPlaceHolder(string templateAlias) - { - return String.Format("", templateAlias.Replace(" ", "")); - } - - private static void ReplaceElement(ref string design, string elementName, string newElementName, bool checkForQuotes) - { - var m = - Regex.Matches(design, GetElementRegExp(elementName, checkForQuotes), - RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - - foreach (Match match in m) - { - GroupCollection groups = match.Groups; - - // generate new element (compensate for a closing trail on single elements ("/")) - string elementAttributes = groups[1].Value; - // test for macro alias - if (elementName == "?UMBRACO_MACRO") - { - var tags = XmlHelper.GetAttributesFromElement(match.Value); - if (tags["macroAlias"] != null) - elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroAlias"]) + elementAttributes; - else if (tags["macroalias"] != null) - elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroalias"]) + elementAttributes; - } - string newElement = "<" + newElementName + " runat=\"server\" " + elementAttributes.Trim() + ">"; - if (elementAttributes.EndsWith("/")) - { - elementAttributes = elementAttributes.Substring(0, elementAttributes.Length - 1); - } - else if (groups[0].Value.StartsWith(""; - - if (checkForQuotes) - { - // if it's inside quotes, we'll change element attribute quotes to single quotes - newElement = newElement.Replace("\"", "'"); - newElement = String.Format("\"{0}\"", newElement); - } - design = design.Replace(match.Value, newElement); - } - } - - private static string GetElementRegExp(string elementName, bool checkForQuotes) - { - if (checkForQuotes) - return String.Format("\"<[^>\\s]*\\b{0}(\\b[^>]*)>\"", elementName); - else - return String.Format("<[^>\\s]*\\b{0}(\\b[^>]*)>", elementName); - - } - - } -} diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index 4ea3ed64d5..8bea82ea4a 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -18,10 +18,6 @@ namespace Umbraco.Core.IO public static string Install => "~/install"; - //fixme: remove this - [Obsolete("Master pages are obsolete and code should be removed")] - public static string Masterpages => "~/masterpages"; - public static string AppCode => "~/App_Code"; public static string AppPlugins => "~/App_Plugins"; diff --git a/src/Umbraco.Core/Models/ITemplate.cs b/src/Umbraco.Core/Models/ITemplate.cs index 97b9324415..6548a49626 100644 --- a/src/Umbraco.Core/Models/ITemplate.cs +++ b/src/Umbraco.Core/Models/ITemplate.cs @@ -1,11 +1,9 @@ -using System; -using System.Runtime.Serialization; -using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { /// - /// Defines a Template File (Masterpage or Mvc View) + /// Defines a Template File (Mvc View) /// public interface ITemplate : IFile, IRememberBeingDirty, ICanBeDirty { diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 2e9fee9595..9bea527b91 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -1234,10 +1234,7 @@ namespace Umbraco.Core.Packaging var alias = templateElement.Element("Alias").Value; var design = templateElement.Element("Design").Value; var masterElement = templateElement.Element("Master"); - - var isMasterPage = IsMasterPageSyntax(design); - var path = isMasterPage ? MasterpagePath(alias) : ViewPath(alias); - + var existingTemplate = _fileService.GetTemplate(alias) as Template; var template = existingTemplate ?? new Template(templateName, alias); template.Content = design; @@ -1257,23 +1254,11 @@ namespace Umbraco.Core.Packaging return templates; } - - private bool IsMasterPageSyntax(string code) - { - return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || - code.InvariantContains(" GetDescendants(int masterTemplateId); IEnumerable GetDescendants(string alias); - /// - /// This checks what the default rendering engine is set in config but then also ensures that there isn't already - /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate - /// rendering engine to use. - /// - /// - /// - /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx - /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml - /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. - /// This is mostly related to installing packages since packages install file templates to the file system and then create the - /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. - /// - RenderingEngine DetermineTemplateRenderingEngine(ITemplate template); - /// /// Validates a /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs index 19ef303ebe..ac0f4f0bed 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -23,20 +22,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement ///
internal class TemplateRepository : NPocoRepositoryBase, ITemplateRepository { - private readonly IFileSystem _masterpagesFileSystem; private readonly IFileSystem _viewsFileSystem; - private readonly ITemplatesSection _templateConfig; private readonly ViewHelper _viewHelper; - private readonly MasterPageHelper _masterPageHelper; - public TemplateRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, ITemplatesSection templateConfig, IFileSystems fileSystems) + public TemplateRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, IFileSystems fileSystems) : base(scopeAccessor, cache, logger) { - _masterpagesFileSystem = fileSystems.MasterPagesFileSystem; _viewsFileSystem = fileSystems.MvcViewsFileSystem; - _templateConfig = templateConfig; _viewHelper = new ViewHelper(_viewsFileSystem); - _masterPageHelper = new MasterPageHelper(_masterpagesFileSystem); } protected override IRepositoryCachePolicy CreateCachePolicy() @@ -255,18 +248,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement else { // else, create or write template.Content to disk - if (DetermineTemplateRenderingEngine(template) == RenderingEngine.Mvc) - { - content = originalAlias == null - ? _viewHelper.CreateView(template, true) - : _viewHelper.UpdateViewFile(template, originalAlias); - } - else - { - content = originalAlias == null - ? _masterPageHelper.CreateMasterPage(template, this, true) - : _masterPageHelper.UpdateMasterPageFile(template, originalAlias, this); - } + content = originalAlias == null + ? _viewHelper.CreateView(template, true) + : _viewHelper.UpdateViewFile(template, originalAlias); } // once content has been set, "template on disk" are not "on disk" anymore @@ -298,16 +282,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Database.Execute(delete, new { id = GetEntityId(entity) }); } - if (DetermineTemplateRenderingEngine(entity) == RenderingEngine.Mvc) - { - var viewName = string.Concat(entity.Alias, ".cshtml"); - _viewsFileSystem.DeleteFile(viewName); - } - else - { - var masterpageName = string.Concat(entity.Alias, ".master"); - _masterpagesFileSystem.DeleteFile(masterpageName); - } + var viewName = string.Concat(entity.Alias, ".cshtml"); + _viewsFileSystem.DeleteFile(viewName); entity.DeleteDate = DateTime.Now; } @@ -388,27 +364,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement template.VirtualPath = _viewsFileSystem.GetUrl(path); return; } - path = string.Concat(template.Alias, ".master"); - if (_masterpagesFileSystem.FileExists(path)) - { - template.VirtualPath = _masterpagesFileSystem.GetUrl(path); - return; - } } else { // we know the path already - var ext = Path.GetExtension(path); - switch (ext) - { - case ".cshtml": - case ".vbhtml": - template.VirtualPath = _viewsFileSystem.GetUrl(path); - return; - case ".master": - template.VirtualPath = _masterpagesFileSystem.GetUrl(path); - return; - } + template.VirtualPath = _viewsFileSystem.GetUrl(path); } template.VirtualPath = string.Empty; // file not found... @@ -426,25 +386,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement path = string.Concat(template.Alias, ".vbhtml"); if (_viewsFileSystem.FileExists(path)) return GetFileContent(template, _viewsFileSystem, path, init); - path = string.Concat(template.Alias, ".master"); - if (_masterpagesFileSystem.FileExists(path)) - return GetFileContent(template, _masterpagesFileSystem, path, init); } else { // we know the path already - var ext = Path.GetExtension(path); - switch (ext) - { - case ".cshtml": - case ".vbhtml": - return GetFileContent(template, _viewsFileSystem, path, init); - case ".master": - return GetFileContent(template, _masterpagesFileSystem, path, init); - } + return GetFileContent(template, _viewsFileSystem, path, init); } template.VirtualPath = string.Empty; // file not found... + return string.Empty; } @@ -514,9 +464,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement case ".vbhtml": fs = _viewsFileSystem; break; - case ".master": - fs = _masterpagesFileSystem; - break; default: throw new Exception("Unsupported extension " + ext + "."); } @@ -625,56 +572,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } - /// - /// This checks what the default rendering engine is set in config but then also ensures that there isn't already - /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate - /// rendering engine to use. - /// - /// - /// - /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx - /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml - /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. - /// This is mostly related to installing packages since packages install file templates to the file system and then create the - /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. - /// - public RenderingEngine DetermineTemplateRenderingEngine(ITemplate template) - { - var engine = _templateConfig.DefaultRenderingEngine; - var viewHelper = new ViewHelper(_viewsFileSystem); - if (viewHelper.ViewExists(template) == false) - { - if (template.Content.IsNullOrWhiteSpace() == false && MasterPageHelper.IsMasterPageSyntax(template.Content)) - { - //there is a design but its definitely a webforms design and we haven't got a MVC view already for it - return RenderingEngine.WebForms; - } - } - - var masterPageHelper = new MasterPageHelper(_masterpagesFileSystem); - - switch (engine) - { - case RenderingEngine.Mvc: - //check if there's a view in ~/masterpages - if (masterPageHelper.MasterPageExists(template) && viewHelper.ViewExists(template) == false) - { - //change this to webforms since there's already a file there for this template alias - engine = RenderingEngine.WebForms; - } - break; - case RenderingEngine.WebForms: - //check if there's a view in ~/views - if (viewHelper.ViewExists(template) && masterPageHelper.MasterPageExists(template) == false) - { - //change this to mvc since there's already a file there for this template alias - engine = RenderingEngine.Mvc; - } - break; - } - return engine; - } - /// /// Validates a /// @@ -689,21 +586,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var path = template.VirtualPath; // get valid paths - var validDirs = _templateConfig.DefaultRenderingEngine == RenderingEngine.Mvc - ? new[] { SystemDirectories.Masterpages, SystemDirectories.MvcViews } - : new[] { SystemDirectories.Masterpages }; + var validDirs = new[] { SystemDirectories.MvcViews }; // get valid extensions var validExts = new List(); - if (_templateConfig.DefaultRenderingEngine == RenderingEngine.Mvc) - { - validExts.Add("cshtml"); - validExts.Add("vbhtml"); - } - else - { - validExts.Add("master"); - } + validExts.Add("cshtml"); + validExts.Add("vbhtml"); // validate path and extension var validFile = IOHelper.VerifyEditPath(path, validDirs); diff --git a/src/Umbraco.Core/Services/IFileService.cs b/src/Umbraco.Core/Services/IFileService.cs index 76e850beb2..daf5d9b80c 100644 --- a/src/Umbraco.Core/Services/IFileService.cs +++ b/src/Umbraco.Core/Services/IFileService.cs @@ -210,21 +210,6 @@ namespace Umbraco.Core.Services /// Optional id of the user void SaveTemplate(IEnumerable templates, int userId = 0); - /// - /// This checks what the default rendering engine is set in config but then also ensures that there isn't already - /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate - /// rendering engine to use. - /// - /// - /// - /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx - /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml - /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. - /// This is mostly related to installing packages since packages install file templates to the file system and then create the - /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. - /// - RenderingEngine DetermineTemplateRenderingEngine(ITemplate template); - /// /// Gets the content of a template as a stream. /// diff --git a/src/Umbraco.Core/Services/Implement/FileService.cs b/src/Umbraco.Core/Services/Implement/FileService.cs index f15f0d7d47..0c08404ab3 100644 --- a/src/Umbraco.Core/Services/Implement/FileService.cs +++ b/src/Umbraco.Core/Services/Implement/FileService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -556,27 +555,6 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// This checks what the default rendering engine is set in config but then also ensures that there isn't already - /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate - /// rendering engine to use. - /// - /// - /// - /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx - /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml - /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. - /// This is mostly related to installing packages since packages install file templates to the file system and then create the - /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. - /// - public RenderingEngine DetermineTemplateRenderingEngine(ITemplate template) - { - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) - { - return _templateRepository.DetermineTemplateRenderingEngine(template); - } - } - /// /// Deletes a template by its alias /// @@ -1043,7 +1021,7 @@ namespace Umbraco.Core.Services.Implement _auditRepository.Save(new AuditItem(objectId, type, userId, entityType)); } - //TODO Method to change name and/or alias of view/masterpage template + //TODO Method to change name and/or alias of view template #region Event Handlers diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 13f1ff2025..81c5af104f 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -291,7 +291,6 @@ - @@ -304,7 +303,6 @@ - @@ -631,7 +629,6 @@ - diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementDefaultTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementDefaultTests.cs deleted file mode 100644 index 4f7e8c1800..0000000000 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementDefaultTests.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Configurations.UmbracoSettings -{ - [TestFixture] - public class TemplateElementDefaultTests : TemplateElementTests - { - protected override bool TestingDefaults - { - get { return true; } - } - } -} diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementTests.cs deleted file mode 100644 index a2edf94ab5..0000000000 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/TemplateElementTests.cs +++ /dev/null @@ -1,16 +0,0 @@ -using NUnit.Framework; -using Umbraco.Core; - -namespace Umbraco.Tests.Configurations.UmbracoSettings -{ - [TestFixture] - public class TemplateElementTests : UmbracoSettingsTests - { - [Test] - public void DefaultRenderingEngine() - { - Assert.IsTrue(SettingsSection.Templates.DefaultRenderingEngine == RenderingEngine.Mvc); - } - - } -} diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config index 4c64485503..dd44e23328 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config @@ -145,10 +145,6 @@ - - Mvc - - false true diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.minimal.config b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.minimal.config index 21dfa1f19e..bee7133051 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.minimal.config +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.minimal.config @@ -37,11 +37,6 @@ - - - Mvc - - diff --git a/src/Umbraco.Tests/IO/IoHelperTests.cs b/src/Umbraco.Tests/IO/IoHelperTests.cs index b2ef5e4d31..b0e59cbb55 100644 --- a/src/Umbraco.Tests/IO/IoHelperTests.cs +++ b/src/Umbraco.Tests/IO/IoHelperTests.cs @@ -37,7 +37,6 @@ namespace Umbraco.Tests.IO Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Css, true), IOHelper.MapPath(SystemDirectories.Css, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Data, true), IOHelper.MapPath(SystemDirectories.Data, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Install, true), IOHelper.MapPath(SystemDirectories.Install, false)); - Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Masterpages, true), IOHelper.MapPath(SystemDirectories.Masterpages, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Media, true), IOHelper.MapPath(SystemDirectories.Media, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Packages, true), IOHelper.MapPath(SystemDirectories.Packages, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Preview, true), IOHelper.MapPath(SystemDirectories.Preview, false)); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index aeaf76967f..f3af1cf73f 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -7,12 +7,9 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; using Umbraco.Core.Models; -using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; @@ -36,7 +33,7 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository) { var cacheHelper = CacheHelper.Disabled; - var templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(scopeAccessor, cacheHelper, Logger); contentTypeRepository = new ContentTypeRepository(scopeAccessor, cacheHelper, Logger, templateRepository); var languageRepository = new LanguageRepository(scopeAccessor, cacheHelper, Logger); @@ -46,7 +43,7 @@ namespace Umbraco.Tests.Persistence.Repositories private ContentTypeRepository CreateRepository(IScopeAccessor scopeAccessor) { - var templateRepository = new TemplateRepository(scopeAccessor, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepository = new TemplateRepository(scopeAccessor, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var contentTypeRepository = new ContentTypeRepository(scopeAccessor, CacheHelper.Disabled, Logger, templateRepository); return contentTypeRepository; } @@ -71,7 +68,7 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var templateRepo = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepo = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var repository = CreateRepository((IScopeAccessor) provider); var templates = new[] { diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index c1fa5381ff..2619827705 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -64,7 +64,7 @@ namespace Umbraco.Tests.Persistence.Repositories { cacheHelper = cacheHelper ?? CacheHelper; - templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(scopeAccessor, cacheHelper, Logger); contentTypeRepository = new ContentTypeRepository(scopeAccessor, cacheHelper, Logger, templateRepository); var languageRepository = new LanguageRepository(scopeAccessor, cacheHelper, Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs index a5402f964e..5511114d3e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs @@ -4,9 +4,7 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; @@ -22,7 +20,7 @@ namespace Umbraco.Tests.Persistence.Repositories private DomainRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository, out DocumentRepository documentRepository, out LanguageRepository languageRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepository = new TemplateRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger); contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger, templateRepository); languageRepository = new LanguageRepository(accessor, Core.Cache.CacheHelper.Disabled, Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs index e76d794e69..23d95163d0 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs @@ -4,10 +4,8 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; @@ -307,7 +305,7 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, CacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepository = new TemplateRepository(accessor, CacheHelper, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(accessor, CacheHelper, Logger); contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper, Logger, templateRepository); var languageRepository = new LanguageRepository(accessor, CacheHelper, Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs index 78eb736007..03295ea599 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs @@ -953,7 +953,7 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateContentRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepository = new TemplateRepository(accessor, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(accessor, CacheHelper.Disabled, Logger); contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper.Disabled, Logger, templateRepository); var languageRepository = new LanguageRepository(accessor, CacheHelper.Disabled, Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs index f4bed68315..7d4b413a11 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs @@ -25,11 +25,9 @@ namespace Umbraco.Tests.Persistence.Repositories { private IFileSystems _fileSystems; - private ITemplateRepository CreateRepository(IScopeProvider provider, ITemplatesSection templatesSection = null) + private ITemplateRepository CreateRepository(IScopeProvider provider) { - return new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, - templatesSection ?? Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc), - _fileSystems); + return new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, _fileSystems); } public override void SetUp() @@ -37,8 +35,6 @@ namespace Umbraco.Tests.Persistence.Repositories base.SetUp(); _fileSystems = Mock.Of(); - var masterPageFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages); - Mock.Get(_fileSystems).Setup(x => x.MasterPagesFileSystem).Returns(masterPageFileSystem); var viewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews); Mock.Get(_fileSystems).Setup(x => x.MvcViewsFileSystem).Returns(viewsFileSystem); } @@ -56,77 +52,6 @@ namespace Umbraco.Tests.Persistence.Repositories } } - [Test] - public void Can_Perform_Add_MasterPage_Detect_Content() - { - // Arrange - using (ScopeProvider.CreateScope()) - { - var repository = CreateRepository(ScopeProvider); - - // Act - var template = new Template("test", "test") - { - Content = @"<%@ Master Language=""C#"" %>" - }; - repository.Save(template); - - //Assert - Assert.That(repository.Get("test"), Is.Not.Null); - Assert.That(_fileSystems.MasterPagesFileSystem.FileExists("test.master"), Is.True); - } - } - - [Test] - public void Can_Perform_Add_MasterPage_With_Default_Content() - { - // Arrange - using (ScopeProvider.CreateScope()) - { - var repository = CreateRepository(ScopeProvider, Mock.Of(x => x.DefaultRenderingEngine == RenderingEngine.WebForms)); - - // Act - var template = new Template("test", "test"); - repository.Save(template); - - //Assert - Assert.That(repository.Get("test"), Is.Not.Null); - Assert.That(_fileSystems.MasterPagesFileSystem.FileExists("test.master"), Is.True); - Assert.AreEqual(@"<%@ Master Language=""C#"" MasterPageFile=""~/umbraco/masterpages/default.master"" AutoEventWireup=""true"" %> - - - - -".StripWhitespace(), template.Content.StripWhitespace()); - } - } - - [Test] - public void Can_Perform_Add_MasterPage_With_Default_Content_With_Parent() - { - // Arrange - using (ScopeProvider.CreateScope()) - { - var repository = CreateRepository(ScopeProvider, Mock.Of(x => x.DefaultRenderingEngine == RenderingEngine.WebForms)); - - //NOTE: This has to be persisted first - var template = new Template("test", "test"); - repository.Save(template); - - // Act - var template2 = new Template("test2", "test2"); - template2.SetMasterTemplate(template); - repository.Save(template2); - - //Assert - Assert.That(repository.Get("test2"), Is.Not.Null); - Assert.That(_fileSystems.MasterPagesFileSystem.FileExists("test2.master"), Is.True); - Assert.AreEqual(@"<%@ Master Language=""C#"" MasterPageFile=""~/masterpages/test.master"" AutoEventWireup=""true"" %> - -".StripWhitespace(), template2.Content.StripWhitespace()); - } - } - [Test] public void Can_Perform_Add_View() { @@ -253,32 +178,6 @@ namespace Umbraco.Tests.Persistence.Repositories } } - [Test] - public void Can_Perform_Update_MasterPage() - { - // Arrange - using (ScopeProvider.CreateScope()) - { - var repository = CreateRepository(ScopeProvider); - - // Act - var template = new Template("test", "test") - { - Content = @"<%@ Master Language=""C#"" %>" - }; - repository.Save(template); - - template.Content = @"<%@ Master Language=""VB"" %>"; - repository.Save(template); - - var updated = repository.Get("test"); - - // Assert - Assert.That(_fileSystems.MasterPagesFileSystem.FileExists("test.master"), Is.True); - Assert.That(updated.Content, Is.EqualTo(@"<%@ Master Language=""VB"" %>")); - } - } - [Test] public void Can_Perform_Update_View() { @@ -305,31 +204,6 @@ namespace Umbraco.Tests.Persistence.Repositories } } - [Test] - public void Can_Perform_Delete_MasterPage() - { - // Arrange - using (ScopeProvider.CreateScope()) - { - var repository = CreateRepository(ScopeProvider); - - var template = new Template("test", "test") - { - Content = @"<%@ Master Language=""C#"" %>" - }; - repository.Save(template); - - // Act - var templates = repository.Get("test"); - Assert.That(_fileSystems.MasterPagesFileSystem.FileExists("test.master"), Is.True); - repository.Delete(templates); - - // Assert - Assert.IsNull(repository.Get("test")); - Assert.That(_fileSystems.MasterPagesFileSystem.FileExists("test.master"), Is.False); - } - } - [Test] public void Can_Perform_Delete_View() { @@ -651,11 +525,6 @@ namespace Umbraco.Tests.Persistence.Repositories _fileSystems = null; //Delete all files - var fsMaster = new PhysicalFileSystem(SystemDirectories.Masterpages); - var masterPages = fsMaster.GetFiles("", "*.master"); - foreach (var file in masterPages) - fsMaster.DeleteFile(file); - var fsViews = new PhysicalFileSystem(SystemDirectories.MvcViews); var views = fsViews.GetFiles("", "*.cshtml"); foreach (var file in views) diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 847972cc50..ba2a7de859 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateContentRepository(IScopeProvider provider, out IContentTypeRepository contentTypeRepository, out ITemplateRepository templateRepository) { var accessor = (IScopeAccessor) provider; - templateRepository = new TemplateRepository(accessor, CacheHelper, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + templateRepository = new TemplateRepository(accessor, CacheHelper, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(accessor, CacheHelper, Logger); contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper, Logger, templateRepository); var languageRepository = new LanguageRepository(accessor, CacheHelper, Logger); diff --git a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs index 3aefa88a50..fff88d7531 100644 --- a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs @@ -163,7 +163,7 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); @@ -196,7 +196,7 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); @@ -227,7 +227,7 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); @@ -261,7 +261,7 @@ namespace Umbraco.Tests.Services var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) { - var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var tRepository = new TemplateRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepo = new TagRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger, tRepository); var languageRepository = new LanguageRepository((IScopeAccessor) provider, CacheHelper.Disabled, Logger); diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 0f48a9c99a..a9e48988f4 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -3037,7 +3037,7 @@ namespace Umbraco.Tests.Services private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, CacheHelper.Disabled, Logger, Mock.Of(), TestObjects.GetFileSystemsMock()); + var templateRepository = new TemplateRepository(accessor, CacheHelper.Disabled, Logger, TestObjects.GetFileSystemsMock()); var tagRepository = new TagRepository(accessor, CacheHelper.Disabled, Logger); contentTypeRepository = new ContentTypeRepository(accessor, CacheHelper.Disabled, Logger, templateRepository); var languageRepository = new LanguageRepository(accessor, CacheHelper.Disabled, Logger); diff --git a/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs b/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs deleted file mode 100644 index a8344893c0..0000000000 --- a/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs +++ /dev/null @@ -1,21 +0,0 @@ -using NUnit.Framework; -using Umbraco.Core.IO; - -namespace Umbraco.Tests.Templates -{ - [TestFixture] - public class MasterPageHelperTests - { - - [TestCase(@"<%@ master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] - [TestCase(@"<%@ Master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] - [TestCase(@"<%@Master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] - [TestCase(@"<%@ Master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] - [TestCase(@"<%@master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] - public void IsMasterPageSyntax(string design) - { - Assert.IsTrue(MasterPageHelper.IsMasterPageSyntax(design)); - } - - } -} diff --git a/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs b/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs deleted file mode 100644 index 795d79ced1..0000000000 --- a/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Repositories.Implement; -using Umbraco.Core.Scoping; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Templates -{ - [TestFixture] - public class TemplateRepositoryTests - { - private readonly Mock _cacheMock = new Mock(); - private readonly Mock _templateConfigMock = new Mock(); - private readonly IFileSystems _fileSystems = Mock.Of(); - private TemplateRepository _templateRepository; - - private readonly TestObjects _testObjects = new TestObjects(null); - - [SetUp] - public void Setup() - { - var logger = Mock.Of(); - - var accessorMock = new Mock(); - var scopeMock = new Mock(); - var database = _testObjects.GetUmbracoSqlCeDatabase(logger); - scopeMock.Setup(x => x.Database).Returns(database); - accessorMock.Setup(x => x.AmbientScope).Returns(scopeMock.Object); - - var mvcFs = Mock.Of(); - var masterFs = Mock.Of(); - Mock.Get(_fileSystems).Setup(x => x.MvcViewsFileSystem).Returns(mvcFs); - Mock.Get(_fileSystems).Setup(x => x.MasterPagesFileSystem).Returns(masterFs); - - _templateRepository = new TemplateRepository(accessorMock.Object, _cacheMock.Object, logger, _templateConfigMock.Object, _fileSystems); - } - - [Test] - public void DetermineTemplateRenderingEngine_Returns_MVC_When_ViewFile_Exists_And_Content_Has_Webform_Markup() - { - // Project in MVC mode - _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); - - // Template has masterpage content - var templateMock = new Mock(); - templateMock.Setup(x => x.Alias).Returns("Something"); - templateMock.Setup(x => x.Content).Returns(""); - - // but MVC View already exists - Mock.Get(_fileSystems.MvcViewsFileSystem) - .Setup(x => x.FileExists(It.IsAny())).Returns(true); - - var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); - Assert.AreEqual(RenderingEngine.Mvc, res); - } - - [Test] - public void DetermineTemplateRenderingEngine_Returns_WebForms_When_ViewFile_Doesnt_Exist_And_Content_Has_Webform_Markup() - { - // Project in MVC mode - _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); - - // Template has masterpage content - var templateMock = new Mock(); - templateMock.Setup(x => x.Alias).Returns("Something"); - templateMock.Setup(x => x.Content).Returns(""); - - // MVC View doesn't exist - Mock.Get(_fileSystems.MvcViewsFileSystem) - .Setup(x => x.FileExists(It.IsAny())).Returns(false); - - var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); - Assert.AreEqual(RenderingEngine.WebForms, res); - } - - [Test] - public void DetermineTemplateRenderingEngine_Returns_WebForms_When_MasterPage_Exists_And_In_Mvc_Mode() - { - // Project in MVC mode - _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); - - var templateMock = new Mock(); - templateMock.Setup(x => x.Alias).Returns("Something"); - - // but masterpage already exists - Mock.Get(_fileSystems.MvcViewsFileSystem) - .Setup(x => x.FileExists(It.IsAny())).Returns(false); - Mock.Get(_fileSystems.MasterPagesFileSystem) - .Setup(x => x.FileExists(It.IsAny())).Returns(true); - - var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); - Assert.AreEqual(RenderingEngine.WebForms, res); - } - - [Test] - public void DetermineTemplateRenderingEngine_Returns_Mvc_When_ViewPage_Exists_And_In_Webforms_Mode() - { - // Project in WebForms mode - _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.WebForms); - - var templateMock = new Mock(); - templateMock.Setup(x => x.Alias).Returns("Something"); - - // but MVC View already exists - Mock.Get(_fileSystems.MvcViewsFileSystem) - .Setup(x => x.FileExists(It.IsAny())).Returns(true); - Mock.Get(_fileSystems.MasterPagesFileSystem) - .Setup(x => x.FileExists(It.IsAny())).Returns(false); - - var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); - Assert.AreEqual(RenderingEngine.Mvc, res); - } - - } -} diff --git a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs index ea40ed9c84..cfd935cd82 100644 --- a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs +++ b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs @@ -38,7 +38,6 @@ namespace Umbraco.Tests.TestHelpers var content = new Mock(); var security = new Mock(); var requestHandler = new Mock(); - var templates = new Mock(); var logging = new Mock(); var tasks = new Mock(); var providers = new Mock(); @@ -47,7 +46,6 @@ namespace Umbraco.Tests.TestHelpers settings.Setup(x => x.Content).Returns(content.Object); settings.Setup(x => x.Security).Returns(security.Object); settings.Setup(x => x.RequestHandler).Returns(requestHandler.Object); - settings.Setup(x => x.Templates).Returns(templates.Object); settings.Setup(x => x.Logging).Returns(logging.Object); settings.Setup(x => x.ScheduledTasks).Returns(tasks.Object); settings.Setup(x => x.Providers).Returns(providers.Object); @@ -61,7 +59,6 @@ namespace Umbraco.Tests.TestHelpers settings.Setup(x => x.RequestHandler.UseDomainPrefixes).Returns(false); settings.Setup(x => x.RequestHandler.CharCollection).Returns(RequestHandlerElement.GetDefaultCharReplacements()); settings.Setup(x => x.WebRouting.UrlProviderMode).Returns("AutoLegacy"); - settings.Setup(x => x.Templates.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); settings.Setup(x => x.Providers.DefaultBackOfficeUserProvider).Returns("UsersMembershipProvider"); return settings.Object; diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index 1fe814e4c6..b6f597bf46 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -55,12 +55,12 @@ namespace Umbraco.Tests.TestHelpers public static void InitializeContentDirectories() { - CreateDirectories(new[] { SystemDirectories.Masterpages, SystemDirectories.MvcViews, SystemDirectories.Media, SystemDirectories.AppPlugins }); + CreateDirectories(new[] { SystemDirectories.MvcViews, SystemDirectories.Media, SystemDirectories.AppPlugins }); } public static void CleanContentDirectories() { - CleanDirectories(new[] { SystemDirectories.Masterpages, SystemDirectories.MvcViews, SystemDirectories.Media }); + CleanDirectories(new[] { SystemDirectories.MvcViews, SystemDirectories.Media }); } public static void CreateDirectories(string[] directories) @@ -77,7 +77,6 @@ namespace Umbraco.Tests.TestHelpers { var preserves = new Dictionary { - { SystemDirectories.Masterpages, new[] {"dummy.txt"} }, { SystemDirectories.MvcViews, new[] {"dummy.txt"} } }; foreach (var directory in directories) diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 8c230f98d0..563d81da05 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -145,8 +145,7 @@ namespace Umbraco.Tests.TestHelpers public IFileSystems GetFileSystemsMock() { var fileSystems = Mock.Of(); - - MockFs(fileSystems, x => x.MasterPagesFileSystem); + MockFs(fileSystems, x => x.MacroPartialsFileSystem); MockFs(fileSystems, x => x.MvcViewsFileSystem); MockFs(fileSystems, x => x.PartialViewsFileSystem); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index a79531af74..304a13f20c 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -304,7 +304,6 @@ namespace Umbraco.Tests.Testing // register basic stuff that might need to be there for some container resolvers to work Composition.RegisterUnique(factory => factory.GetInstance().Content); - Composition.RegisterUnique(factory => factory.GetInstance().Templates); Composition.RegisterUnique(factory => factory.GetInstance().WebRouting); Composition.RegisterUnique(factory => ExamineManager.Instance); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e49ba250fa..c22b765169 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -305,8 +305,6 @@ - - @@ -354,7 +352,6 @@ - @@ -453,7 +450,6 @@ - diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index fb8ff63ab0..7299a397bc 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -85,11 +85,6 @@ - - - Mvc - - diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index c3e146d6ce..4de0a04735 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -162,11 +162,6 @@ - - - Mvc - - + + Add between {{model.config.minNumber}} and {{model.config.maxNumber}} items + + You can only have {{model.config.maxNumber}} items selected + + + + + + Add {{model.config.minNumber - renderModel.length}} item(s) + + You can only have {{model.config.maxNumber}} items selected + + + + + + Add up to {{model.config.maxNumber}} items + + You can only have {{model.config.maxNumber}} items selected + + + + + + Add at least {{model.config.minNumber}} item(s) + + + + + + + + +
+ You need to add at least {{model.config.minNumber}} items +
+ +
+ You can only have {{model.config.maxNumber}} items selected +
+ + + + diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index 65d366e2ad..fe85263f3b 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -117,6 +117,7 @@ namespace Umbraco.Web.Cache LegacyMediaPickerPropertyConverter.ClearCaches(); SliderValueConverter.ClearCaches(); MediaPickerPropertyConverter.ClearCaches(); + MultiUrlPickerPropertyConverter.ClearCaches(); base.Refresh(jsonPayload); diff --git a/src/Umbraco.Web/Models/ContentEditing/LinkDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/LinkDisplay.cs new file mode 100644 index 0000000000..857ae2c318 --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/LinkDisplay.cs @@ -0,0 +1,36 @@ +using System.Runtime.Serialization; +using Umbraco.Core; + +namespace Umbraco.Web.Models.ContentEditing +{ + [DataContract(Name = "link", Namespace = "")] + internal class LinkDisplay + { + [DataMember(Name = "icon")] + public string Icon { get; set; } + + [DataMember(Name = "isMedia")] + public bool IsMedia { get; set; } + + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "published")] + public bool Published { get; set; } + + [DataMember(Name = "queryString")] + public string QueryString { get; set; } + + [DataMember(Name = "target")] + public string Target { get; set; } + + [DataMember(Name = "trashed")] + public bool Trashed { get; set; } + + [DataMember(Name = "udi")] + public GuidUdi Udi { get; set; } + + [DataMember(Name = "url")] + public string Url { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/Link.cs b/src/Umbraco.Web/Models/Link.cs new file mode 100644 index 0000000000..74ad4ad2af --- /dev/null +++ b/src/Umbraco.Web/Models/Link.cs @@ -0,0 +1,13 @@ +using Umbraco.Core; + +namespace Umbraco.Web.Models +{ + public class Link + { + public string Name { get; set; } + public string Target { get; set; } + public LinkType Type { get; set; } + public Udi Udi { get; set; } + public string Url { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/LinkType.cs b/src/Umbraco.Web/Models/LinkType.cs new file mode 100644 index 0000000000..3db3165d7f --- /dev/null +++ b/src/Umbraco.Web/Models/LinkType.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Web.Models +{ + public enum LinkType + { + Content, + Media, + External + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs new file mode 100644 index 0000000000..84523f05c4 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.PropertyEditors +{ + [PropertyEditor(Constants.PropertyEditors.MultiUrlPickerAlias, "Multi Url Picker", PropertyEditorValueTypes.Json, "multiurlpicker", Group = "pickers", Icon = "icon-link", IsParameterEditor = true)] + public class MultiUrlPickerPropertyEditor : PropertyEditor + { + protected override PreValueEditor CreatePreValueEditor() + { + return new MultiUrlPickerPreValueEditor(); + } + + protected override PropertyValueEditor CreateValueEditor() + { + return new MultiUrlPickerPropertyValueEditor(base.CreateValueEditor()); + } + + private class MultiUrlPickerPreValueEditor : PreValueEditor + { + public MultiUrlPickerPreValueEditor() + { + Fields.Add(new PreValueField + { + Key = "minNumber", + View = "number", + Name = "Minimum number of items" + }); + Fields.Add(new PreValueField + { + Key = "maxNumber", + View = "number", + Name = "Maximum number of items" + }); + } + } + + private class MultiUrlPickerPropertyValueEditor : PropertyValueEditorWrapper + { + public MultiUrlPickerPropertyValueEditor(PropertyValueEditor wrapped) : base(wrapped) + { + } + + public override object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService) + { + if (property.Value == null) + return Enumerable.Empty(); + + var value = property.Value.ToString(); + + if (string.IsNullOrEmpty(value)) + return Enumerable.Empty(); + + try + { + var umbHelper = new UmbracoHelper(UmbracoContext.Current); + var services = ApplicationContext.Current.Services; + var entityService = services.EntityService; + var contentTypeService = services.ContentTypeService; + string deletedLocalization = null; + string recycleBinLocalization = null; + + var dtos = JsonConvert.DeserializeObject>(value); + + var documentLinks = dtos.FindAll(link => + link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Document + ); + + var mediaLinks = dtos.FindAll(link => + link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Media + ); + + var entities = new List(); + if (documentLinks.Count > 0) + { + entities.AddRange( + entityService.GetAll(UmbracoObjectTypes.Document, + documentLinks.Select(link => link.Udi.Guid).ToArray()) + ); + } + + if (mediaLinks.Count > 0) + { + entities.AddRange( + entityService.GetAll(UmbracoObjectTypes.Media, + mediaLinks.Select(link => link.Udi.Guid).ToArray()) + ); + } + + var links = new List(); + foreach (var dto in dtos) + { + var link = new LinkDisplay + { + Icon = "icon-link", + IsMedia = false, + Name = dto.Name, + Published = true, + QueryString = dto.QueryString, + Target = dto.Target, + Trashed = false, + Udi = dto.Udi, + Url = dto.Url, + }; + + links.Add(link); + + if (dto.Udi == null) + continue; + + var entity = entities.Find(e => e.Key == dto.Udi.Guid); + if (entity == null) + { + if (deletedLocalization == null) + deletedLocalization = services.TextService.Localize("general/deleted"); + + link.Published = false; + link.Trashed = true; + link.Url = deletedLocalization; + } + else + { + var entityType = + Equals(entity.AdditionalData["NodeObjectTypeId"], Constants.ObjectTypes.MediaGuid) + ? Constants.UdiEntityType.Media + : Constants.UdiEntityType.Document; + + var udi = new GuidUdi(entityType, entity.Key); + + var contentTypeAlias = (string)entity.AdditionalData["ContentTypeAlias"]; + if (entity.Trashed) + { + if (recycleBinLocalization == null) + recycleBinLocalization = services.TextService.Localize("general/recycleBin"); + + link.Trashed = true; + link.Url = recycleBinLocalization; + } + + if (udi.EntityType == Constants.UdiEntityType.Document) + { + var contentType = contentTypeService.GetContentType(contentTypeAlias); + + if (contentType == null) + continue; + + link.Icon = contentType.Icon; + link.Published = Equals(entity.AdditionalData["IsPublished"], true); + + if (link.Trashed == false) + link.Url = umbHelper.Url(entity.Id, UrlProviderMode.Relative); + } + else + { + link.IsMedia = true; + + var mediaType = contentTypeService.GetMediaType(contentTypeAlias); + + if (mediaType == null) + continue; + + link.Icon = mediaType.Icon; + + if (link.Trashed) + continue; + + var media = umbHelper.TypedMedia(entity.Id); + if (media != null) + link.Url = media.Url; + } + } + } + return links; + } + catch (Exception ex) + { + ApplicationContext.Current.ProfilingLogger.Logger.Error($"Error getting links.\r\n{property.Value}", ex); + } + + return base.ConvertDbToEditor(property, propertyType, dataTypeService); + } + + public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue) + { + if (editorValue.Value == null) + return null; + + var value = editorValue.Value.ToString(); + + if (string.IsNullOrEmpty(value)) + return null; + + try + { + return JsonConvert.SerializeObject( + from link in JsonConvert.DeserializeObject>(value) + select new LinkDto + { + Name = link.Name, + QueryString = link.QueryString, + Target = link.Target, + Udi = link.Udi, + Url = link.Udi == null ? link.Url : null, // only save the url for external links + }, + new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + } + catch (Exception ex) + { + ApplicationContext.Current.ProfilingLogger.Logger.Error($"Error saving links.\r\n{editorValue.Value}", ex); + } + return base.ConvertEditorToDb(editorValue, currentValue); + } + } + + [DataContract] + internal class LinkDto + { + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "queryString")] + public string QueryString { get; set; } + + [DataMember(Name = "target")] + public string Target { get; set; } + + [DataMember(Name = "udi")] + public GuidUdi Udi { get; set; } + + [DataMember(Name = "url")] + public string Url { get; set; } + } + } +} diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs index 3aaf191fd2..541dccaa4e 100644 --- a/src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs @@ -1,10 +1,13 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.RelatedLinks2Alias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.Json, Icon = "icon-thumbnail-list", Group = "pickers")] + // TODO: Remove in V8 + [Obsolete("This editor is obsolete, use MultiUrlPickerPropertyEditor instead")] + [PropertyEditor(Constants.PropertyEditors.RelatedLinks2Alias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.Json, Icon = "icon-thumbnail-list", Group = "pickers", IsDeprecated = true)] public class RelatedLinks2PropertyEditor : PropertyEditor { public RelatedLinks2PropertyEditor() @@ -33,4 +36,4 @@ namespace Umbraco.Web.PropertyEditors public int Maximum { get; set; } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiUrlPickerPropertyConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiUrlPickerPropertyConverter.cs new file mode 100644 index 0000000000..397448983a --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiUrlPickerPropertyConverter.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.ValueConverters; +using Umbraco.Core.Services; +using Umbraco.Web.Models; + +namespace Umbraco.Web.PropertyEditors.ValueConverters +{ + [DefaultPropertyValueConverter(typeof(JsonValueConverter))] + public class MultiUrlPickerPropertyConverter : PropertyValueConverterBase, IPropertyValueConverterMeta + { + private readonly IDataTypeService _dataTypeService; + + public MultiUrlPickerPropertyConverter(IDataTypeService dataTypeService) + { + if (dataTypeService == null) throw new ArgumentNullException("dataTypeService"); + _dataTypeService = dataTypeService; + } + + //TODO: Remove this ctor in v8 since the other one will use IoC + public MultiUrlPickerPropertyConverter() : this(ApplicationContext.Current.Services.DataTypeService) + { + } + + public override bool IsConverter(PublishedPropertyType propertyType) + { + return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.MultiUrlPickerAlias); + } + + public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) + { + if (source == null) + return null; + + if (source.ToString().Trim().StartsWith("[") == false) + return null; + + try + { + return JArray.Parse(source.ToString()); + } + catch (Exception ex) + { + LogHelper.Error("Error parsing JSON", ex); + } + return null; + } + + public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview) + { + var isMultiple = IsMultipleDataType(propertyType.DataTypeId, out var maxNumber); + if (source == null) + return isMultiple + ? Enumerable.Empty() + : null; + + //TODO: Inject an UmbracoHelper and create a GetUmbracoHelper method based on either injected or singleton + if (UmbracoContext.Current == null) + return source; + + var umbHelper = new UmbracoHelper(UmbracoContext.Current); + + var links = new List(); + var dtos = ((JArray) source).ToObject>(); + + foreach (var dto in dtos) + { + var type = LinkType.External; + var url = dto.Url; + if (dto.Udi != null) + { + type = dto.Udi.EntityType == Constants.UdiEntityType.Media + ? LinkType.Media + : LinkType.Content; + + if (type == LinkType.Media) + { + var media = umbHelper.TypedMedia(dto.Udi); + if (media == null) + continue; + url = media.Url; + } + else + { + var content = umbHelper.TypedContent(dto.Udi); + if (content == null) + continue; + url = content.Url; + } + } + + var link = new Link + { + Name = dto.Name, + Target = dto.Target, + Type = type, + Udi = dto.Udi, + Url = url + dto.QueryString, + }; + + links.Add(link); + } + + if (isMultiple == false) + return links.FirstOrDefault(); + if (maxNumber > 0) + return links.Take(maxNumber); + + return links; + } + + public Type GetPropertyValueType(PublishedPropertyType propertyType) + { + return IsMultipleDataType(propertyType.DataTypeId, out var maxNumber) + ? typeof(IEnumerable) + : typeof(Link); + } + + public PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue) + { + switch (cacheValue) + { + case PropertyCacheValue.Source: + return PropertyCacheLevel.Content; + case PropertyCacheValue.Object: + case PropertyCacheValue.XPath: + return PropertyCacheLevel.ContentCache; + } + + return PropertyCacheLevel.None; + } + + private bool IsMultipleDataType(int dataTypeId, out int maxNumber) + { + // GetPreValuesCollectionByDataTypeId is cached at repository level; + // still, the collection is deep-cloned so this is kinda expensive, + // better to cache here + trigger refresh in DataTypeCacheRefresher + + maxNumber = Storages.GetOrAdd(dataTypeId, id => + { + var preValues = _dataTypeService.GetPreValuesCollectionByDataTypeId(id).PreValuesAsDictionary; + + return preValues.TryGetValue("maxNumber", out var maxNumberPreValue) + ? maxNumberPreValue.Value.TryConvertTo().Result + : 0; + }); + + return maxNumber != 1; + } + + private static readonly ConcurrentDictionary Storages = new ConcurrentDictionary(); + + internal static void ClearCaches() + { + Storages.Clear(); + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index e021de0011..1b668b06c8 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -419,6 +419,7 @@ + @@ -444,6 +445,8 @@ + + @@ -485,6 +488,7 @@ + @@ -499,6 +503,7 @@ + From d6855d18f967092dec5583169c535dece072bab4 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 20 Jan 2019 21:19:06 +0100 Subject: [PATCH 217/223] v8: Nicer delete language confirm (#4108) --- .../src/less/components/html/umb-alert.less | 12 +++- .../src/less/utilities/_spacing.less | 13 ++-- .../src/views/languages/overlays/delete.html | 9 +++ .../views/languages/overview.controller.js | 53 ++++++++++------ .../src/views/languages/overview.html | 61 +++++++++---------- .../listview/overlays/delete.html | 4 +- .../listview/overlays/listviewpublish.html | 5 +- .../listview/overlays/listviewunpublish.html | 5 +- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 14 +++++ src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 4 +- .../Umbraco/config/lang/en_us.xml | 1 + 11 files changed, 116 insertions(+), 65 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/languages/overlays/delete.html diff --git a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-alert.less b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-alert.less index ef8834f767..c9aff190ce 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-alert.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-alert.less @@ -8,4 +8,14 @@ .umb-alert--info { background-color: @turquoise-washed; border: 1px solid @turquoise; -} \ No newline at end of file +} + +.umb-alert--warning { + background-color: @yellow-washed; + border: 1px solid @yellow; +} + +.umb-alert--danger { + background-color: @red-washed; + border: 1px solid @red; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less b/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less index 64d86d7b6f..69bbeef0af 100644 --- a/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less +++ b/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less @@ -1,7 +1,5 @@ /* - Spacing - */ @spacing-none: 0; @@ -37,13 +35,11 @@ 7 = 7th step in spacing scale */ - .m-center { margin-left: auto; margin-right: auto; } - .mt0 { margin-top: @spacing-none; } .mt1 { margin-top: @spacing-extra-small; } .mt2 { margin-top: @spacing-small; } @@ -52,3 +48,12 @@ .mt5 { margin-top: @spacing-extra-large; } .mt6 { margin-top: @spacing-extra-extra-large; } .mt7 { margin-top: @spacing-extra-extra-extra-large; } + +.mb0 { margin-bottom: @spacing-none; } +.mb1 { margin-bottom: @spacing-extra-small; } +.mb2 { margin-bottom: @spacing-small; } +.mb3 { margin-bottom: @spacing-medium; } +.mb4 { margin-bottom: @spacing-large; } +.mb5 { margin-bottom: @spacing-extra-large; } +.mb6 { margin-bottom: @spacing-extra-extra-large; } +.mb7 { margin-bottom: @spacing-extra-extra-extra-large; } diff --git a/src/Umbraco.Web.UI.Client/src/views/languages/overlays/delete.html b/src/Umbraco.Web.UI.Client/src/views/languages/overlays/delete.html new file mode 100644 index 0000000000..59221fcea8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/languages/overlays/delete.html @@ -0,0 +1,9 @@ +
+ +
+ This will delete the language {{model.language.name}} [{{model.language.culture}}]. +
+ + ? + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/languages/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/languages/overview.controller.js index a5c446dfb5..c1972ec067 100644 --- a/src/Umbraco.Web.UI.Client/src/views/languages/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/languages/overview.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function LanguagesOverviewController($location, $timeout, navigationService, notificationsService, localizationService, languageResource, eventsService) { + function LanguagesOverviewController($location, $timeout, navigationService, localizationService, languageResource, eventsService, overlayService) { var vm = this; @@ -65,30 +65,47 @@ } function deleteLanguage(language, event) { - var confirmed = confirm("Are you sure you want to delete " + language.name + "?"); - if(confirmed) { - language.deleteButtonState = "busy"; - languageResource.deleteById(language.id).then(function () { + const dialog = { + view: "views/languages/overlays/delete.html", + language: language, + submitButtonLabelKey: "contentTypeEditor_yesDelete", + submit: function (model) { + performDelete(model.language); + overlayService.close(); + }, + close: function () { + overlayService.close(); + } + }; - // emit event - var args = { language: language }; - eventsService.emit("editors.languages.languageDeleted", args); + localizationService.localize("general_delete").then(value => { + dialog.title = value; + overlayService.open(dialog); + }); - // remove from list - var index = vm.languages.indexOf(language); - vm.languages.splice(index, 1); - - }, function (err) { - language.deleteButtonState = "error"; - - }); - - } event.preventDefault() event.stopPropagation(); } + function performDelete(language) { + language.deleteButtonState = "busy"; + + languageResource.deleteById(language.id).then(function () { + + // emit event + var args = { language: language }; + eventsService.emit("editors.languages.languageDeleted", args); + + // remove from list + var index = vm.languages.indexOf(language); + vm.languages.splice(index, 1); + + }, function (err) { + language.deleteButtonState = "error"; + }); + } + init(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/languages/overview.html b/src/Umbraco.Web.UI.Client/src/views/languages/overview.html index c55ce83417..15a9c84367 100644 --- a/src/Umbraco.Web.UI.Client/src/views/languages/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/languages/overview.html @@ -2,43 +2,41 @@ - + - + - + - + - + - - + + - + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/delete.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/delete.html index 6ae3eba521..9b10b1d8b4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/delete.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/delete.html @@ -1,6 +1,6 @@
-
+
This will delete the node and all its languages. If you only want to delete one language go and unpublish it instead. @@ -8,4 +8,4 @@ ? -
\ No newline at end of file +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html index 0e2ced411c..8354b323fa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewpublish.html @@ -6,7 +6,7 @@
-
+

@@ -16,7 +16,7 @@
-
+
- \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html index 03f91b1ad6..5cc46c5ce5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/overlays/listviewunpublish.html @@ -8,13 +8,13 @@
-
+

-
+
- \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index b10f3d0be0..a257fb41d5 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -354,6 +354,7 @@ Indsæt link Indsæt makro Indsæt tabel + Dette vil slette sproget Sidst redigeret Link Internt link: @@ -407,6 +408,7 @@ konto Vælg editor Vælg snippet + Dette vil slette noden og alle dets sprog. Hvis du kun vil slette et sprog, så afpublicér det i stedet. Vis på medlemsprofil fane har ingen sorteringsrækkefølge + + Tilføj sprog + Påkrævet sprog + Egenskaber på dette sprog skal være udfyldt før noden kan blive udgivet. + Standard sprog + Et Umbraco site kan kun have et standard sprog. + Ved at skifte standardsprog kan resultere i standard indhold mangler. + Fallsback til + Ingen fallback sprog + For at tillade flersproget indhold til at falde tilbage på et andet sprog, hvis det ikke er tilgængelig i det anmodet sprog, vælg det her. + Fallback sprog + Alternativt felt Alternativ tekst diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 99a35a5e3b..42a2c4c844 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -371,6 +371,7 @@ Insert link Click to add a Macro Insert table + This will delete the language Last Edited Link Internal link: @@ -429,6 +430,7 @@ account Select editor Select snippet + This will delete the node and all its languages. If you only want to delete one language go and unpublish it instead. Hide History Icon - Id + Id Import Info Inner margin 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 47f293c2a9..be33ee853a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -399,6 +399,7 @@ Insert link Click to add a Macro Insert table + This will delete the language Last Edited Link Internal link: From a502be606ba331f6e32761eae9d14a981ed1c75b Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 20 Jan 2019 21:27:32 +0100 Subject: [PATCH 218/223] v8: Fix package localization (#4159) --- .../src/views/packages/edit.controller.js | 16 ++- .../src/views/packages/edit.html | 2 - .../src/views/packages/options.html | 2 +- .../src/views/packages/overview.controller.js | 119 +++++++++++------- .../src/views/packages/views/created.html | 8 +- .../views/packages/views/install-local.html | 3 - .../src/views/users/overview.controller.js | 3 +- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 9 +- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 13 +- .../Umbraco/config/lang/en_us.xml | 16 ++- 10 files changed, 120 insertions(+), 71 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 0a44192041..282fd0472c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function EditController($scope, $location, $routeParams, umbRequestHelper, entityResource, packageResource, editorService, formHelper) { + function EditController($scope, $location, $routeParams, umbRequestHelper, entityResource, packageResource, editorService, formHelper, localizationService) { const vm = this; @@ -23,18 +23,23 @@ vm.removePackageView = removePackageView; vm.downloadFile = downloadFile; + vm.buttonLabel = ""; + const packageId = $routeParams.id; const create = $routeParams.create; function onInit() { - if(create) { + if (create) { //pre populate package with some values packageResource.getEmpty().then(scaffold => { vm.package = scaffold; vm.loading = false; }); - vm.buttonLabel = "Create"; + + localizationService.localize("general_create").then(function(value) { + vm.buttonLabel = value; + }); } else { // load package packageResource.getCreatedById(packageId).then(createdPackage => { @@ -49,7 +54,10 @@ } }); - vm.buttonLabel = "Save"; + + localizationService.localize("buttons_save").then(function (value) { + vm.buttonLabel = value; + }); } // get all doc types diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 5ad5ac2522..4c32e7e10c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -323,8 +323,6 @@ disabled="vm.loading"> - - diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/options.html b/src/Umbraco.Web.UI.Client/src/views/packages/options.html index d75604d094..f34ac77ac2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/options.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/options.html @@ -19,7 +19,7 @@

- This package has no configuration view + This package has no configuration view

+ label="Create package" + label-key="packager_createPackage"> @@ -24,7 +25,7 @@
{{ createdPackage.name }}
- {{ createdPackage.version }} | {{ createdPackage.url }}| {{ createdPackage.author }} + {{ createdPackage.version }} | {{ createdPackage.url }} | {{ createdPackage.author }}
@@ -34,7 +35,6 @@ button-style="danger" size="xxs" label-key="general_delete" - add-ellipsis="true" action="vm.deleteCreatedPackage($event, $index, createdPackage)"> @@ -45,7 +45,7 @@ - No packages have been created yet + No packages have been created yet
\ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html index b657c42877..6d95bcafa7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.html @@ -41,7 +41,6 @@
-

Upload package

Install a local package by selecting it from your machine. Only install packages from sources you know and trust. @@ -167,8 +166,6 @@

{{vm.installState.status}}

- -
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js index 49e8007d8c..80e2322f6b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/overview.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function UsersOverviewController($scope, $location, $timeout, navigationService, localizationService) { + function UsersOverviewController($scope, $location, localizationService) { var vm = this; var usersUri = $location.search().subview; @@ -24,7 +24,6 @@ loadNavigation(); setPageName(); - } function loadNavigation() { diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index a257fb41d5..0742541484 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -804,6 +804,8 @@ Mange hilsner fra Umbraco robotten Notificeringer + Oprettet + Opret pakke Vælg pakken fra din computer. Umbraco pakker er oftest en ".zip" fil Slip her for at uploade eller klik her for at vælge pakkefil @@ -815,8 +817,12 @@ Mange hilsner fra Umbraco robotten Jeg accepterer betingelser for anvendelse Installér pakke - Afslut + Installeret Installeret pakker + Installér lokal + Afslut + Denne pakke har ingen konfigurationsvisning + Der er ikke blevet oprettet nogle pakker endnu Du har ingen pakker installeret 'Pakker' øverst til højre på din skærm]]> Søg efter pakker @@ -953,6 +959,7 @@ Mange hilsner fra Umbraco robotten Umbraco konfigurationsguide Mediearkiv Medlemmer + Pakker Nyhedsbreve Indstillinger Statistik diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 42a2c4c844..a057bb060f 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1049,6 +1049,8 @@ To manage your website, simply open the Umbraco back office and start adding con Notifications + Created + Create package button and locating the package. Umbraco packages usually have a ".umb" or ".zip" extension. @@ -1063,8 +1065,12 @@ To manage your website, simply open the Umbraco back office and start adding con I accept terms of use Install package - Finish + Installed Installed packages + Install local + Finish + This package has no configuration view + No packages have been created yet You don’t have any packages installed 'Packages' icon in the top right of your screen]]> Search for packages @@ -1212,16 +1218,17 @@ To manage your website, simply open the Umbraco back office and start adding con Content Courier Developer + Forms + Help Umbraco Configuration Wizard Media Members Newsletters + Packages Settings Statistics Translation Users - Help - Forms The best Umbraco video tutorials 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 be33ee853a..8ce9282d71 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -606,7 +606,7 @@ Hide History Icon - Id + Id Import Info Inner margin @@ -657,7 +657,7 @@ Permissions Scheduled Publishing Search - Sorry, we can not find what you are looking for. + Sorry, we can not find what you are looking for. No items have been added Server Settings @@ -1075,6 +1075,8 @@ To manage your website, simply open the Umbraco back office and start adding con Notifications + Created + Create package button and locating the package. Umbraco packages usually have a ".umb" or ".zip" extension. @@ -1089,8 +1091,12 @@ To manage your website, simply open the Umbraco back office and start adding con I accept terms of use Install package - Finish + Installed Installed packages + Install local + Finish + This package has no configuration view + No packages have been created yet You don’t have any packages installed 'Packages' icon in the top right of your screen]]> Search for packages @@ -1239,13 +1245,13 @@ To manage your website, simply open the Umbraco back office and start adding con Content - Packages + Forms Media Members + Packages Settings Translation Users - Forms The best Umbraco video tutorials From d5c6e0c6e7fa9a85af51f1e99b99c9ccd114a2d5 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 21 Jan 2019 09:10:08 +0100 Subject: [PATCH 219/223] - Saving paramters --- src/Umbraco.Core/Collections/ObservableDictionary.cs | 12 ++++++++++++ src/Umbraco.Web/Editors/MacrosController.cs | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Collections/ObservableDictionary.cs b/src/Umbraco.Core/Collections/ObservableDictionary.cs index 6518533476..40269aa4eb 100644 --- a/src/Umbraco.Core/Collections/ObservableDictionary.cs +++ b/src/Umbraco.Core/Collections/ObservableDictionary.cs @@ -125,6 +125,18 @@ namespace Umbraco.Core.Collections } + public void ReplaceAll(IEnumerable values) + { + if (values == null) throw new ArgumentNullException(nameof(values)); + + Clear(); + + foreach (var value in values) + { + Add(value); + } + } + public bool Remove(TKey key) { if (!Indecies.ContainsKey(key)) return false; diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 933de89635..5ff2f7bf34 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -149,6 +149,7 @@ macro.UseInEditor = macroDisplay.UseInEditor; macro.MacroSource = macroDisplay.View; macro.MacroType = MacroTypes.PartialView; + macro.Properties.ReplaceAll(macroDisplay.Parameters.Select((x,i) => new MacroProperty(x.Key, x.Label, i, x.Editor))); try { @@ -218,7 +219,7 @@ } /// - /// Finds all the macro partials + /// Finds all the macro partials /// /// /// The . From 3fd8c6354275115405528f9a1261be7376b92c88 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 21 Jan 2019 09:10:39 +0100 Subject: [PATCH 220/223] - Show Ids - Hide "Render in rich text editor and the grid" if "Use in rich text editor and the grid" is false --- .../src/views/macros/views/settings.html | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html index ba5b324837..59ccf2bc7e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -1,8 +1,17 @@  + + + + {{model.macro.id}}
+ {{model.macro.key}} +
+
+
+ - @@ -13,9 +22,9 @@ - - - + + + From 2744afab001214c71eac37daa15a6273e05a02df Mon Sep 17 00:00:00 2001 From: Matthew-Wise Date: Mon, 21 Jan 2019 08:49:00 +0000 Subject: [PATCH 221/223] Disable LastPass on page heading (#4153) --- .../util/noPasswordManager.directive.js | 24 +++++++++++++++++++ .../components/editor/umb-editor-header.html | 4 +++- .../views/components/umb-locked-field.html | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js new file mode 100644 index 0000000000..190c504aa6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js @@ -0,0 +1,24 @@ +/** +* @ngdoc directive +* @name umbraco.directives.directive:no-password-manager +* @attribte +* @function +* @description +* Added attributes to block password manager elements should as LastPass + +* @example +* +* +* +* +* +**/ +angular.module("umbraco.directives") + .directive('noPasswordManager', function () { + return { + restrict: 'A', + link: function (scope, element, attrs) { + element.attr("data-lpignore", "true"); + } + } + }); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html index 3754b66c53..25925f42ed 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html @@ -23,7 +23,8 @@
- {{ name }}
Date: Mon, 21 Jan 2019 10:44:11 +0100 Subject: [PATCH 222/223] Delete macros --- .../src/common/resources/macro.resource.js | 6 ++++ .../src/views/macros/delete.html | 10 ++++++ .../views/macros/macros.delete.controller.js | 32 +++++++++++++++++++ src/Umbraco.Web/Editors/MacrosController.cs | 16 ++++++++++ src/Umbraco.Web/Trees/MacrosTreeController.cs | 13 ++------ 5 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/delete.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/macros/macros.delete.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index a5d960a9ec..73a1651b5e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -115,6 +115,12 @@ function macroResource($q, $http, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("macroApiBaseUrl", "Save"), macro) ); + }, + + deleteById: function(id) { + return umbRequestHelper.resourcePromise( + $http.post(umbRequestHelper.getApiUrl("macroApiBaseUrl", "deleteById", { "id": id })) + ); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/delete.html b/src/Umbraco.Web.UI.Client/src/views/macros/delete.html new file mode 100644 index 0000000000..2d097e110b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/delete.html @@ -0,0 +1,10 @@ +
+
+ +

+ Are you sure you want to delete {{vm.name}} ? +

+ + +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.delete.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.delete.controller.js new file mode 100644 index 0000000000..1aadef9f31 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.delete.controller.js @@ -0,0 +1,32 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.DeleteController + * @function + * + * @description + * The controller for deleting macro items + */ +function MacrosDeleteController($scope, $location, macroResource, navigationService, treeService) { + var vm = this; + + vm.name = $scope.currentNode.name; + function performDelete() { + $scope.currentNode.loading = true; + macroResource.deleteById($scope.currentNode.id).then(function () { + $scope.currentNode.loading = false; + + treeService.removeNode($scope.currentNode); + + navigationService.hideMenu(); + }); + } + + function cancel() { + navigationService.hideDialog(); + } + + vm.performDelete = performDelete; + vm.cancel = cancel; +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.DeleteController", MacrosDeleteController); diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 5ff2f7bf34..4c198ea6b3 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -115,6 +115,22 @@ return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); } + + [HttpPost] + public HttpResponseMessage DeleteById(int id) + { + var macro = this.Services.MacroService.GetById(id); + + if (macro == null) + { + return this.ReturnErrorResponse($"Macro with id {id} does not exist"); + } + + this.Services.MacroService.Delete(macro); + + return Request.CreateResponse(HttpStatusCode.OK); + } + [HttpPost] public HttpResponseMessage Save(MacroDisplay macroDisplay) { diff --git a/src/Umbraco.Web/Trees/MacrosTreeController.cs b/src/Umbraco.Web/Trees/MacrosTreeController.cs index cdbe4bfcf7..0300dbd6c6 100644 --- a/src/Umbraco.Web/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/MacrosTreeController.cs @@ -54,7 +54,7 @@ namespace Umbraco.Web.Trees { //Create the normal create action menu.Items.Add(Services.TextService); - + //refresh action menu.Items.Add(new RefreshNode(Services.TextService, true)); @@ -65,16 +65,7 @@ namespace Umbraco.Web.Trees if (macro == null) return new MenuItemCollection(); //add delete option for all macros - menu.Items.Add(Services.TextService, opensDialog: true) - //Since we haven't implemented anything for macros in angular, this needs to be converted to - //use the legacy format - .ConvertLegacyMenuItem(new EntitySlim - { - Id = macro.Id, - Level = 1, - ParentId = -1, - Name = macro.Name - }, "macros", queryStrings.GetValue("application")); + menu.Items.Add(Services.TextService, opensDialog: true); return menu; } From 57902892f9066d72621d38adcfc3978fc36f4b70 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 21 Jan 2019 10:55:48 +0100 Subject: [PATCH 223/223] Constructor injection --- .../Editors/MacroRenderingController.cs | 18 ++++++++----- src/Umbraco.Web/Editors/MacrosController.cs | 27 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web/Editors/MacroRenderingController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs index 08ff4ca44b..0b4a78e603 100644 --- a/src/Umbraco.Web/Editors/MacroRenderingController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -15,6 +15,7 @@ using Umbraco.Web.Macros; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Services; namespace Umbraco.Web.Editors { @@ -29,11 +30,14 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class MacroRenderingController : UmbracoAuthorizedJsonController, IRequiresSessionState { + private readonly IMacroService _macroService; + private readonly IContentService _contentService; private readonly IVariationContextAccessor _variationContextAccessor; - - public MacroRenderingController(IVariationContextAccessor variationContextAccessor) + public MacroRenderingController(IVariationContextAccessor variationContextAccessor, IMacroService macroService, IContentService contentService) { _variationContextAccessor = variationContextAccessor; + _macroService = macroService; + _contentService = contentService; } /// @@ -41,12 +45,12 @@ namespace Umbraco.Web.Editors /// /// /// - /// Note that ALL logged in users have access to this method because editors will need to isnert macros into rte (content/media/members) and it's used for + /// Note that ALL logged in users have access to this method because editors will need to insert macros into rte (content/media/members) and it's used for /// inserting into templates/views/etc... it doesn't expose any sensitive data. /// public IEnumerable GetMacroParameters(int macroId) { - var macro = Services.MacroService.GetById(macroId); + var macro = _macroService.GetById(macroId); if (macro == null) { throw new HttpResponseException(HttpStatusCode.NotFound); @@ -97,13 +101,13 @@ namespace Umbraco.Web.Editors { // note - here we should be using the cache, provided that the preview content is in the cache... - var doc = Services.ContentService.GetById(pageId); + var doc = _contentService.GetById(pageId); if (doc == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } - var m = Services.MacroService.GetByAlias(macroAlias); + var m = _macroService.GetByAlias(macroAlias); if (m == null) throw new HttpResponseException(HttpStatusCode.NotFound); var macro = new MacroModel(m); @@ -166,7 +170,7 @@ namespace Umbraco.Web.Editors MacroSource = model.VirtualPath.EnsureStartsWith("~") }; - Services.MacroService.Save(macro); // may throw + _macroService.Save(macro); // may throw return new HttpResponseMessage(HttpStatusCode.OK); } diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 4c198ea6b3..84cd1911c3 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Web.Editors +using Umbraco.Core.Services; + +namespace Umbraco.Web.Editors { using System; using System.Collections.Generic; @@ -28,6 +30,13 @@ [UmbracoTreeAuthorize(Constants.Trees.Macros)] public class MacrosController : BackOfficeNotificationsController { + private readonly IMacroService _macroService; + + public MacrosController(IMacroService macroService) + { + _macroService = macroService; + } + /// /// Creates a new macro /// @@ -47,7 +56,7 @@ var alias = name.ToSafeAlias(); - if (this.Services.MacroService.GetByAlias(alias) != null) + if (_macroService.GetByAlias(alias) != null) { return this.ReturnErrorResponse("Macro with this alias already exists"); } @@ -62,7 +71,7 @@ MacroType = MacroTypes.PartialView }; - this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); + _macroService.Save(macro, this.Security.CurrentUser.Id); return this.Request.CreateResponse(HttpStatusCode.OK, macro.Id); } @@ -75,7 +84,7 @@ [HttpGet] public HttpResponseMessage GetById(int id) { - var macro = this.Services.MacroService.GetById(id); + var macro = _macroService.GetById(id); if (macro == null) { @@ -119,14 +128,14 @@ [HttpPost] public HttpResponseMessage DeleteById(int id) { - var macro = this.Services.MacroService.GetById(id); + var macro = _macroService.GetById(id); if (macro == null) { return this.ReturnErrorResponse($"Macro with id {id} does not exist"); } - this.Services.MacroService.Delete(macro); + _macroService.Delete(macro); return Request.CreateResponse(HttpStatusCode.OK); } @@ -139,7 +148,7 @@ return this.ReturnErrorResponse($"No macro data found in request"); } - var macro = this.Services.MacroService.GetById(int.Parse(macroDisplay.Id.ToString())); + var macro = _macroService.GetById(int.Parse(macroDisplay.Id.ToString())); if (macro == null) { @@ -148,7 +157,7 @@ if (macroDisplay.Alias != macro.Alias) { - var macroByAlias = this.Services.MacroService.GetByAlias(macroDisplay.Alias); + var macroByAlias = _macroService.GetByAlias(macroDisplay.Alias); if (macroByAlias != null) { @@ -169,7 +178,7 @@ try { - this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); + _macroService.Save(macro, this.Security.CurrentUser.Id); macroDisplay.Notifications.Clear();
LanguageLanguage ISODefaultMandatoryDefaultMandatory Fallback
{{ language.name }} @@ -47,17 +45,15 @@ {{ language.culture }} - + - + @@ -65,14 +61,13 @@ (none) - +