From 7f7456701d8acd3d6651a13c298b58e66daa8cba Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Tue, 2 Jul 2013 15:32:53 +0200 Subject: [PATCH 01/25] Adding license --- LICENSE.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..c5560c3ce1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +# The MIT License (MIT) # + +Copyright (c) 2013 Umbraco + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 0d54e8df893582867d58bff9864694ffb5e3caed Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 11:00:26 +0200 Subject: [PATCH 02/25] Updating MySql package dependency --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- src/Umbraco.Web.UI/packages.config | 2 +- src/Umbraco.Web.UI/web.Template.config | 2 +- src/umbraco.datalayer/packages.config | 2 +- src/umbraco.datalayer/umbraco.datalayer.csproj | 5 +++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index fb738c1110..24ba93de8d 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -131,9 +131,9 @@ False ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - + False - ..\packages\MySql.Data.6.6.4\lib\net40\MySql.Data.dll + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll False diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config index d1ed9ea678..3e93300cff 100644 --- a/src/Umbraco.Web.UI/packages.config +++ b/src/Umbraco.Web.UI/packages.config @@ -17,7 +17,7 @@ - + diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 008f10c001..f439b4c0a7 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -62,7 +62,7 @@ - + diff --git a/src/umbraco.datalayer/packages.config b/src/umbraco.datalayer/packages.config index 87b5ad1860..02379f5503 100644 --- a/src/umbraco.datalayer/packages.config +++ b/src/umbraco.datalayer/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/src/umbraco.datalayer/umbraco.datalayer.csproj b/src/umbraco.datalayer/umbraco.datalayer.csproj index fd27b2b076..05e6b10167 100644 --- a/src/umbraco.datalayer/umbraco.datalayer.csproj +++ b/src/umbraco.datalayer/umbraco.datalayer.csproj @@ -74,8 +74,9 @@ False ..\packages\Microsoft.ApplicationBlocks.Data.1.0.1559.20655\lib\Microsoft.ApplicationBlocks.Data.dll - - ..\packages\MySql.Data.6.6.4\lib\net40\MySql.Data.dll + + False + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll From 9d4e1362c491f781850cadb854a2c9a267d5ad09 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 11:11:37 +0200 Subject: [PATCH 03/25] Updating nuget references for ASP.NET MVC, Razor, WebPages and WebApi to latest patch release --- src/Umbraco.Core/Umbraco.Core.csproj | 12 ++++++------ src/Umbraco.Core/packages.config | 6 +++--- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 18 +++++++++--------- src/Umbraco.Web.UI/packages.config | 14 +++++++------- src/Umbraco.Web/Umbraco.Web.csproj | 18 +++++++++--------- src/Umbraco.Web/packages.config | 14 +++++++------- src/umbraco.MacroEngines/packages.config | 14 +++++++------- .../umbraco.MacroEngines.csproj | 18 +++++++++--------- src/umbraco.businesslogic/packages.config | 6 +++--- .../umbraco.businesslogic.csproj | 12 ++++++------ 10 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d424140a95..38094eacc6 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -68,28 +68,28 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll True - ..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll True - ..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll diff --git a/src/Umbraco.Core/packages.config b/src/Umbraco.Core/packages.config index ba4f62ac37..f1d5aa83c6 100644 --- a/src/Umbraco.Core/packages.config +++ b/src/Umbraco.Core/packages.config @@ -1,9 +1,9 @@  - - - + + + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 24ba93de8d..c1895a6004 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -170,7 +170,7 @@ ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll - ..\packages\Microsoft.AspNet.WebApi.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll @@ -188,36 +188,36 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll - ..\packages\Microsoft.AspNet.WebApi.Core.4.0.20710.0\lib\net40\System.Web.Http.dll + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll - ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.20710.0\lib\net40\System.Web.Http.WebHost.dll + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll True - ..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll True - ..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll System.Web.Services True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll System.XML diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config index 3e93300cff..79bd38ebd9 100644 --- a/src/Umbraco.Web.UI/packages.config +++ b/src/Umbraco.Web.UI/packages.config @@ -5,14 +5,14 @@ - + - - - - - - + + + + + + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 6b75dd32b2..3040070e69 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -163,7 +163,7 @@ ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll - ..\packages\Microsoft.AspNet.WebApi.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll @@ -179,28 +179,28 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll - ..\packages\Microsoft.AspNet.WebApi.Core.4.0.20710.0\lib\net40\System.Web.Http.dll + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll - ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.20710.0\lib\net40\System.Web.Http.WebHost.dll + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll True - ..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll True - ..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll System.Web.Services True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll True @@ -208,11 +208,11 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index d370ef28d5..5dd2f0a1bd 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -5,14 +5,14 @@ - + - - - - - - + + + + + + diff --git a/src/umbraco.MacroEngines/packages.config b/src/umbraco.MacroEngines/packages.config index f76f93a114..ffc685e2d6 100644 --- a/src/umbraco.MacroEngines/packages.config +++ b/src/umbraco.MacroEngines/packages.config @@ -3,13 +3,13 @@ - - - - - - - + + + + + + + diff --git a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj index 418782fd71..9e03046369 100644 --- a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj +++ b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj @@ -74,7 +74,7 @@ ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll - ..\packages\Microsoft.AspNet.WebApi.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll @@ -82,33 +82,33 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll - ..\packages\Microsoft.AspNet.WebApi.Core.4.0.20710.0\lib\net40\System.Web.Http.dll + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll - ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.20710.0\lib\net40\System.Web.Http.WebHost.dll + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll True - ..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll True - ..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll diff --git a/src/umbraco.businesslogic/packages.config b/src/umbraco.businesslogic/packages.config index 8fb83abb39..3bf5121413 100644 --- a/src/umbraco.businesslogic/packages.config +++ b/src/umbraco.businesslogic/packages.config @@ -1,7 +1,7 @@  - - - + + + \ No newline at end of file diff --git a/src/umbraco.businesslogic/umbraco.businesslogic.csproj b/src/umbraco.businesslogic/umbraco.businesslogic.csproj index 7586e83e68..7d1e446b27 100644 --- a/src/umbraco.businesslogic/umbraco.businesslogic.csproj +++ b/src/umbraco.businesslogic/umbraco.businesslogic.csproj @@ -123,27 +123,27 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll True - ..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll True - ..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll System.XML From f06a6f42dacd86bb94c042eacc7e3140d0995ac3 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 11:20:42 +0200 Subject: [PATCH 04/25] Updating nuget dependency for ClientDependency --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 8 ++++---- src/Umbraco.Web.UI/packages.config | 4 ++-- src/Umbraco.Web/Umbraco.Web.csproj | 4 ++-- src/Umbraco.Web/packages.config | 2 +- src/umbraco.cms/packages.config | 2 +- src/umbraco.cms/umbraco.cms.csproj | 4 ++-- src/umbraco.controls/packages.config | 2 +- src/umbraco.controls/umbraco.controls.csproj | 4 ++-- src/umbraco.editorControls/packages.config | 2 +- src/umbraco.editorControls/umbraco.editorControls.csproj | 4 ++-- src/umbraco.macroRenderings/packages.config | 2 +- .../umbraco.macroRenderings.csproj | 4 ++-- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index c1895a6004..8e2ca750c1 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -100,13 +100,13 @@ {07fbc26b-2927-4a22-8d96-d644c667fecc} UmbracoExamine - + False - ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll + ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll - + False - ..\packages\ClientDependency-Mvc.1.7.0.0\lib\ClientDependency.Core.Mvc.dll + ..\packages\ClientDependency-Mvc.1.7.0.3\lib\ClientDependency.Core.Mvc.dll False diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config index 79bd38ebd9..a481c72581 100644 --- a/src/Umbraco.Web.UI/packages.config +++ b/src/Umbraco.Web.UI/packages.config @@ -1,7 +1,7 @@  - - + + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3040070e69..fef122489e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -93,9 +93,9 @@ {07fbc26b-2927-4a22-8d96-d644c667fecc} UmbracoExamine - + False - ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll + ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll False diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index 5dd2f0a1bd..03cc60e40f 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/umbraco.cms/packages.config b/src/umbraco.cms/packages.config index 06959d20f2..63f606279c 100644 --- a/src/umbraco.cms/packages.config +++ b/src/umbraco.cms/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index bd584b2d9b..68502bb22e 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -104,9 +104,9 @@ AllRules.ruleset - + False - ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll + ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll False diff --git a/src/umbraco.controls/packages.config b/src/umbraco.controls/packages.config index babc1d8a83..d30bbbe9c0 100644 --- a/src/umbraco.controls/packages.config +++ b/src/umbraco.controls/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/umbraco.controls/umbraco.controls.csproj b/src/umbraco.controls/umbraco.controls.csproj index 6ab376e99b..daf27f279f 100644 --- a/src/umbraco.controls/umbraco.controls.csproj +++ b/src/umbraco.controls/umbraco.controls.csproj @@ -66,9 +66,9 @@ AllRules.ruleset - + False - ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll + ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll diff --git a/src/umbraco.editorControls/packages.config b/src/umbraco.editorControls/packages.config index babc1d8a83..d30bbbe9c0 100644 --- a/src/umbraco.editorControls/packages.config +++ b/src/umbraco.editorControls/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/umbraco.editorControls/umbraco.editorControls.csproj b/src/umbraco.editorControls/umbraco.editorControls.csproj index 729e160c02..bdd3e23fc1 100644 --- a/src/umbraco.editorControls/umbraco.editorControls.csproj +++ b/src/umbraco.editorControls/umbraco.editorControls.csproj @@ -112,9 +112,9 @@ {651E1350-91B6-44B7-BD60-7207006D7003} Umbraco.Web - + False - ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll + ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll System diff --git a/src/umbraco.macroRenderings/packages.config b/src/umbraco.macroRenderings/packages.config index 2a8355e1b9..c840bab970 100644 --- a/src/umbraco.macroRenderings/packages.config +++ b/src/umbraco.macroRenderings/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/umbraco.macroRenderings/umbraco.macroRenderings.csproj b/src/umbraco.macroRenderings/umbraco.macroRenderings.csproj index 83985d444f..c07eff239b 100644 --- a/src/umbraco.macroRenderings/umbraco.macroRenderings.csproj +++ b/src/umbraco.macroRenderings/umbraco.macroRenderings.csproj @@ -104,9 +104,9 @@ AllRules.ruleset - + False - ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll + ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll False From 6609bc09f20162bc8d27e762dd87d28b20286a9d Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 11:26:17 +0200 Subject: [PATCH 05/25] Updating nuget dependency for HtmlAgilityPack --- src/Umbraco.Web/Umbraco.Web.csproj | 4 ++-- src/Umbraco.Web/packages.config | 2 +- src/umbraco.MacroEngines/packages.config | 2 +- src/umbraco.MacroEngines/umbraco.MacroEngines.csproj | 4 ++-- src/umbraco.cms/packages.config | 2 +- src/umbraco.cms/umbraco.cms.csproj | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index fef122489e..ab431d6c84 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -105,9 +105,9 @@ False ..\packages\Examine.0.1.51.2941\lib\Examine.dll - + False - ..\packages\HtmlAgilityPack.1.4.5\lib\Net40\HtmlAgilityPack.dll + ..\packages\HtmlAgilityPack.1.4.6\lib\Net40\HtmlAgilityPack.dll False diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index 03cc60e40f..9590b4fc69 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -3,7 +3,7 @@ - + diff --git a/src/umbraco.MacroEngines/packages.config b/src/umbraco.MacroEngines/packages.config index ffc685e2d6..023ebfc6b9 100644 --- a/src/umbraco.MacroEngines/packages.config +++ b/src/umbraco.MacroEngines/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj index 9e03046369..90f8e01edc 100644 --- a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj +++ b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj @@ -46,9 +46,9 @@ False ..\packages\Examine.0.1.51.2941\lib\Examine.dll - + False - ..\packages\HtmlAgilityPack.1.4.5\lib\Net40\HtmlAgilityPack.dll + ..\packages\HtmlAgilityPack.1.4.6\lib\Net40\HtmlAgilityPack.dll False diff --git a/src/umbraco.cms/packages.config b/src/umbraco.cms/packages.config index 63f606279c..3a63559557 100644 --- a/src/umbraco.cms/packages.config +++ b/src/umbraco.cms/packages.config @@ -1,7 +1,7 @@  - + \ No newline at end of file diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index 68502bb22e..d51da1be04 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -108,9 +108,9 @@ False ..\packages\ClientDependency.1.7.0.3\lib\ClientDependency.Core.dll - + False - ..\packages\HtmlAgilityPack.1.4.5\lib\Net40\HtmlAgilityPack.dll + ..\packages\HtmlAgilityPack.1.4.6\lib\Net40\HtmlAgilityPack.dll False From 69c5aeb1b3c30c9093edd9c876f55018a274254d Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 11:29:58 +0200 Subject: [PATCH 06/25] Updating nuget dependencies for test project --- src/Umbraco.Tests/Umbraco.Tests.csproj | 18 +++++++++--------- src/Umbraco.Tests/packages.config | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 6514db0ace..e4d21a8039 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -95,7 +95,7 @@ ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll - ..\packages\Microsoft.AspNet.WebApi.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll @@ -104,33 +104,33 @@ True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll - ..\packages\Microsoft.AspNet.WebApi.Core.4.0.20710.0\lib\net40\System.Web.Http.dll + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll - ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.20710.0\lib\net40\System.Web.Http.WebHost.dll + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll True - ..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll True - ..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll True - ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll diff --git a/src/Umbraco.Tests/packages.config b/src/Umbraco.Tests/packages.config index 4f69076931..f1e2902ce8 100644 --- a/src/Umbraco.Tests/packages.config +++ b/src/Umbraco.Tests/packages.config @@ -3,13 +3,13 @@ - - - - - - - + + + + + + + From aed70ae40c3536db7f0f11d962bef552480e6642 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 11:46:53 +0200 Subject: [PATCH 07/25] Updating dependencies in our own nuspec file --- build/NuSpecs/UmbracoCms.Core.nuspec | 9 ++++----- src/umbraco.sln | 11 +++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 32dab6f4a3..996f05936a 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -19,22 +19,21 @@ - + - + + + - - - diff --git a/src/umbraco.sln b/src/umbraco.sln index 3d2ab0be28..fee2486039 100644 --- a/src/umbraco.sln +++ b/src/umbraco.sln @@ -61,6 +61,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UmbracoExamine.Azure", "Umb EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UmbracoExamine.PDF.Azure", "UmbracoExamine.PDF.Azure\UmbracoExamine.PDF.Azure.csproj", "{B555AAE6-0F56-442F-AC9F-EF497DB38DE7}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{227C3B55-80E5-4E7E-A802-BE16C5128B9D}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\UmbracoCms.Core.nuspec = ..\build\NuSpecs\UmbracoCms.Core.nuspec + ..\build\NuSpecs\UmbracoCms.nuspec = ..\build\NuSpecs\UmbracoCms.nuspec + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -107,10 +113,6 @@ Global {6EDD2061-82F2-461B-BB6E-879245A832DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EDD2061-82F2-461B-BB6E-879245A832DE}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EDD2061-82F2-461B-BB6E-879245A832DE}.Release|Any CPU.Build.0 = Release|Any CPU - {CBDB56AC-FF02-4421-9FD4-ED82E339D8E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CBDB56AC-FF02-4421-9FD4-ED82E339D8E2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CBDB56AC-FF02-4421-9FD4-ED82E339D8E2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CBDB56AC-FF02-4421-9FD4-ED82E339D8E2}.Release|Any CPU.Build.0 = Release|Any CPU {5BA5425F-27A7-4677-865E-82246498AA2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5BA5425F-27A7-4677-865E-82246498AA2E}.Debug|Any CPU.Build.0 = Debug|Any CPU {5BA5425F-27A7-4677-865E-82246498AA2E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -148,6 +150,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {227C3B55-80E5-4E7E-A802-BE16C5128B9D} = {2849E9D4-3B4E-40A3-A309-F3CB4F0E125F} {5D3B8245-ADA6-453F-A008-50ED04BFE770} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} {07FBC26B-2927-4A22-8D96-D644C667FECC} = {DD32977B-EF54-475B-9A1B-B97A502C6E58} {F30DDDB8-3994-4673-82AE-057123C6E1A8} = {DD32977B-EF54-475B-9A1B-B97A502C6E58} From e280785f4805ad62b34b2c3b0a88bc73dffddd9c Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 12:30:34 +0200 Subject: [PATCH 08/25] Adding Msdeploy PropertyGroup to build prop file, so both FileSystem and MsDeploy package will include the umbraco and umbraco_client folders --- build/NuSpecs/build/net40/UmbracoCms.props | 5 +++++ build/NuSpecs/build/net45/UmbracoCms.props | 5 +++++ build/NuSpecs/build/net451/UmbracoCms.props | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/build/NuSpecs/build/net40/UmbracoCms.props b/build/NuSpecs/build/net40/UmbracoCms.props index 50c21a7c0d..5e11945a9d 100644 --- a/build/NuSpecs/build/net40/UmbracoCms.props +++ b/build/NuSpecs/build/net40/UmbracoCms.props @@ -5,5 +5,10 @@ AddUmbracoFilesToOutput; $(CopyAllFilesToSingleFolderForPackageDependsOn); + + + AddUmbracoFilesToOutput; + $(CopyAllFilesToSingleFolderForPackageDependsOn); + \ No newline at end of file diff --git a/build/NuSpecs/build/net45/UmbracoCms.props b/build/NuSpecs/build/net45/UmbracoCms.props index 50c21a7c0d..5e11945a9d 100644 --- a/build/NuSpecs/build/net45/UmbracoCms.props +++ b/build/NuSpecs/build/net45/UmbracoCms.props @@ -5,5 +5,10 @@ AddUmbracoFilesToOutput; $(CopyAllFilesToSingleFolderForPackageDependsOn); + + + AddUmbracoFilesToOutput; + $(CopyAllFilesToSingleFolderForPackageDependsOn); + \ No newline at end of file diff --git a/build/NuSpecs/build/net451/UmbracoCms.props b/build/NuSpecs/build/net451/UmbracoCms.props index 50c21a7c0d..5e11945a9d 100644 --- a/build/NuSpecs/build/net451/UmbracoCms.props +++ b/build/NuSpecs/build/net451/UmbracoCms.props @@ -5,5 +5,10 @@ AddUmbracoFilesToOutput; $(CopyAllFilesToSingleFolderForPackageDependsOn); + + + AddUmbracoFilesToOutput; + $(CopyAllFilesToSingleFolderForPackageDependsOn); + \ No newline at end of file From aeece499bb72881466f97825c85356271155e70b Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Jul 2013 14:00:44 +0200 Subject: [PATCH 09/25] Fixing unit test for PublishedMedia cache, which had expected result set incorrect --- src/Umbraco.Tests/PublishedCache/PublishedMediaCacheTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/PublishedCache/PublishedMediaCacheTests.cs index a1d922e86d..d795ebe18d 100644 --- a/src/Umbraco.Tests/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/PublishedCache/PublishedMediaCacheTests.cs @@ -61,7 +61,7 @@ namespace Umbraco.Tests.PublishedCache Assert.AreEqual(mRoot.Id, publishedMedia.Id); Assert.AreEqual(mRoot.CreateDateTime.ToString("dd/MM/yyyy HH:mm:ss"), publishedMedia.CreateDate.ToString("dd/MM/yyyy HH:mm:ss")); Assert.AreEqual(mRoot.User.Id, publishedMedia.CreatorId); - Assert.AreEqual(mRoot.User.Name, publishedMedia.CreatorName); + Assert.AreEqual(mRoot.User.LoginName, publishedMedia.CreatorName); Assert.AreEqual(mRoot.ContentType.Alias, publishedMedia.DocumentTypeAlias); Assert.AreEqual(mRoot.ContentType.Id, publishedMedia.DocumentTypeId); Assert.AreEqual(mRoot.Level, publishedMedia.Level); From d015780b9f4e778e0cde8ff5ef692e2ac14085af Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Jul 2013 12:13:02 +1000 Subject: [PATCH 10/25] Fixes: #U4-2447 - non thread safe icon lookup --- src/umbraco.cms/businesslogic/CMSNode.cs | 68 ++++++++++++++++-------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/src/umbraco.cms/businesslogic/CMSNode.cs b/src/umbraco.cms/businesslogic/CMSNode.cs index 76455c1361..8032f381d0 100644 --- a/src/umbraco.cms/businesslogic/CMSNode.cs +++ b/src/umbraco.cms/businesslogic/CMSNode.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Threading; using System.Xml; +using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Caching; @@ -55,12 +57,13 @@ namespace umbraco.cms.businesslogic #region Private static - private static readonly string m_DefaultIconCssFile = IOHelper.MapPath(SystemDirectories.Umbraco_client + "/Tree/treeIcons.css"); - private static List m_DefaultIconClasses = new List(); + private static readonly string DefaultIconCssFile = IOHelper.MapPath(SystemDirectories.Umbraco_client + "/Tree/treeIcons.css"); + private static readonly List InternalDefaultIconClasses = new List(); + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); - private static void initializeIconClasses() + private static void InitializeIconClasses() { - StreamReader re = File.OpenText(m_DefaultIconCssFile); + StreamReader re = File.OpenText(DefaultIconCssFile); string content = string.Empty; string input = null; while ((input = re.ReadLine()) != null) @@ -70,20 +73,20 @@ namespace umbraco.cms.businesslogic re.Close(); // parse the classes - MatchCollection m = Regex.Matches(content, "([^{]*){([^}]*)}", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + var m = Regex.Matches(content, "([^{]*){([^}]*)}", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); foreach (Match match in m) { - GroupCollection groups = match.Groups; - string cssClass = groups[1].Value.Replace("\n", "").Replace("\r", "").Trim().Trim(Environment.NewLine.ToCharArray()); - if (!String.IsNullOrEmpty(cssClass)) + var groups = match.Groups; + var cssClass = groups[1].Value.Replace("\n", "").Replace("\r", "").Trim().Trim(Environment.NewLine.ToCharArray()); + if (string.IsNullOrEmpty(cssClass) == false) { - m_DefaultIconClasses.Add(cssClass); + InternalDefaultIconClasses.Add(cssClass); } } } - private const string m_SQLSingle = "SELECT id, createDate, trashed, parentId, nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text FROM umbracoNode WHERE id = @id"; - private const string m_SQLDescendants = @" + private const string SqlSingle = "SELECT id, createDate, trashed, parentId, nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text FROM umbracoNode WHERE id = @id"; + private const string SqlDescendants = @" SELECT id, createDate, trashed, parentId, nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text FROM umbracoNode WHERE path LIKE '%,{0},%'"; @@ -137,10 +140,16 @@ namespace umbraco.cms.businesslogic { get { - if (m_DefaultIconClasses.Count == 0) - initializeIconClasses(); + using (var l = new UpgradeableReadLock(Locker)) + { + if (InternalDefaultIconClasses.Count == 0) + { + l.UpgradeToWriteLock(); + InitializeIconClasses(); + } + return InternalDefaultIconClasses; + } - return m_DefaultIconClasses; } } @@ -309,7 +318,7 @@ namespace umbraco.cms.businesslogic return sortOrder; } - + /// /// Retrieve a list of the id's of all CMSNodes given the objecttype and the first letter of the name. /// @@ -519,9 +528,9 @@ order by level,sortOrder"; SqlHelper.CreateParameter("@parentId", newParent.Id)); this.Parent = newParent; - this.sortOrder = maxSortOrder + 1; + this.sortOrder = maxSortOrder + 1; } - + //detect if we have moved, then update the level and path // issue: http://issues.umbraco.org/issue/U4-1579 if (this.Path != newParent.Path + "," + this.Id.ToString()) @@ -556,7 +565,7 @@ order by level,sortOrder"; //regenerate the xml for the newParent node var parentDocument = new Document(newParent.Id); parentDocument.XmlGenerate(new XmlDocument()); - + } else if (!IsTrashed && newParent.nodeObjectType == Media._objectType) { @@ -661,7 +670,7 @@ order by level,sortOrder"; public virtual IEnumerable GetDescendants() { var descendants = new List(); - using (IRecordsReader dr = SqlHelper.ExecuteReader(string.Format(m_SQLDescendants, Id))) + using (IRecordsReader dr = SqlHelper.ExecuteReader(string.Format(SqlDescendants, Id))) { while (dr.Read()) { @@ -998,7 +1007,7 @@ order by level,sortOrder"; /// protected virtual void setupNode() { - using (IRecordsReader dr = SqlHelper.ExecuteReader(m_SQLSingle, + using (IRecordsReader dr = SqlHelper.ExecuteReader(SqlSingle, SqlHelper.CreateParameter("@id", this.Id))) { if (dr.Read()) @@ -1105,7 +1114,7 @@ order by level,sortOrder"; _isTrashed = dr.GetBoolean("trashed"); } - internal protected void PopulateCMSNodeFromUmbracoEntity(IUmbracoEntity content, Guid objectType) + internal protected void PopulateCMSNodeFromContentBase(IContentBase content, Guid objectType) { _uniqueID = content.Key; _nodeObjectType = objectType; @@ -1120,6 +1129,21 @@ order by level,sortOrder"; _entity = content; } + internal protected void PopulateCMSNodeFromContentTypeBase(IContentTypeBase contentType, Guid objectType) + { + _uniqueID = contentType.Key; + _nodeObjectType = objectType; + _level = contentType.Level; + _path = contentType.Path; + _parentid = contentType.ParentId; + _text = contentType.Name; + _sortOrder = contentType.SortOrder; + _userId = contentType.CreatorId; + _createDate = contentType.CreateDate; + _isTrashed = false; + _entity = contentType; + } + #endregion #region Private Methods @@ -1187,7 +1211,7 @@ order by level,sortOrder"; } /// - /// Occurs after a node is saved. + /// Occurs after a node is saved. /// public static event EventHandler AfterSave; From 0683094f849cab12d3a5d4d8d8994142733cbfca Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Jul 2013 12:20:25 +1000 Subject: [PATCH 11/25] oops, overwrote previous changes to CmsNode, now merged them back in properly. --- src/umbraco.cms/businesslogic/CMSNode.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/umbraco.cms/businesslogic/CMSNode.cs b/src/umbraco.cms/businesslogic/CMSNode.cs index 8032f381d0..ba8a6ccc35 100644 --- a/src/umbraco.cms/businesslogic/CMSNode.cs +++ b/src/umbraco.cms/businesslogic/CMSNode.cs @@ -1114,7 +1114,7 @@ order by level,sortOrder"; _isTrashed = dr.GetBoolean("trashed"); } - internal protected void PopulateCMSNodeFromContentBase(IContentBase content, Guid objectType) + internal protected void PopulateCMSNodeFromUmbracoEntity(IUmbracoEntity content, Guid objectType) { _uniqueID = content.Key; _nodeObjectType = objectType; @@ -1129,21 +1129,6 @@ order by level,sortOrder"; _entity = content; } - internal protected void PopulateCMSNodeFromContentTypeBase(IContentTypeBase contentType, Guid objectType) - { - _uniqueID = contentType.Key; - _nodeObjectType = objectType; - _level = contentType.Level; - _path = contentType.Path; - _parentid = contentType.ParentId; - _text = contentType.Name; - _sortOrder = contentType.SortOrder; - _userId = contentType.CreatorId; - _createDate = contentType.CreateDate; - _isTrashed = false; - _entity = contentType; - } - #endregion #region Private Methods From 7ff0e6cd4b89e56f5b08b96d5fe4b0c7c4de5be0 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Thu, 4 Jul 2013 10:50:02 +0200 Subject: [PATCH 12/25] Fixes #U4-2458 --- src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 2c92517b15..49e7f1df48 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -510,7 +510,7 @@ namespace Umbraco.Core.Persistence.Repositories var sql = new Sql(); sql.Select("*") .From() - .Where(x => x.ParentId == parentId && x.Text.StartsWith(nodeName)); + .Where(x => x.NodeObjectType == NodeObjectTypeId && x.ParentId == parentId && x.Text.StartsWith(nodeName)); int uniqueNumber = 1; var currentName = nodeName; From e34c857f6c7902dac45f14856f8fc445db38b438 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Thu, 4 Jul 2013 11:22:59 +0200 Subject: [PATCH 13/25] A bit of refactoring around unique naming, and implementing it for media as well --- .../Repositories/ContentRepository.cs | 40 ----------------- .../Repositories/MediaRepository.cs | 44 ++++++++++++++++++ .../Repositories/SimilarNodeNameComparer.cs | 45 +++++++++++++++++++ .../Persistence/RepositoryFactory.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + 5 files changed, 91 insertions(+), 41 deletions(-) create mode 100644 src/Umbraco.Core/Persistence/Repositories/SimilarNodeNameComparer.cs diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 49e7f1df48..58b07e1583 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -533,45 +533,5 @@ namespace Umbraco.Core.Persistence.Repositories return currentName; } - - /// - /// Comparer that takes into account the duplicate index of a node name - /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. - /// - private class SimilarNodeNameComparer : IComparer - { - public int Compare(string x, string y) - { - if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) - { - if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) - { - int xDuplicateIndex = ExtractDuplicateIndex(x); - int yDuplicateIndex = ExtractDuplicateIndex(y); - - if (xDuplicateIndex != 0 && yDuplicateIndex != 0) - { - return xDuplicateIndex.CompareTo(yDuplicateIndex); - } - } - } - return String.Compare(x.ToLower(), y.ToLower(), StringComparison.Ordinal); - } - - private int ExtractDuplicateIndex(string text) - { - int index = 0; - - if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) - { - int startPos = text.LastIndexOf('(') + 1; - int length = text.Length - 1 - startPos; - - int.TryParse(text.Substring(startPos, length), out index); - } - - return index; - } - } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index 81ec056f0a..94b8a21859 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -25,14 +25,20 @@ namespace Umbraco.Core.Persistence.Repositories : base(work) { _mediaTypeRepository = mediaTypeRepository; + + EnsureUniqueNaming = true; } public MediaRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMediaTypeRepository mediaTypeRepository) : base(work, cache) { _mediaTypeRepository = mediaTypeRepository; + + EnsureUniqueNaming = true; } + public bool EnsureUniqueNaming { get; set; } + #region Overrides of RepositoryBase protected override IMedia PerformGet(int id) @@ -182,6 +188,9 @@ namespace Umbraco.Core.Persistence.Repositories { ((Models.Media)entity).AddingEntity(); + //Ensure unique name on the same level + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name); + var factory = new MediaFactory(NodeObjectTypeId, entity.Id); var dto = factory.BuildDto(entity); @@ -246,6 +255,9 @@ namespace Umbraco.Core.Persistence.Repositories //Updates Modified date ((Models.Media)entity).UpdatingEntity(); + //Ensure unique name on the same level + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name); + //Look up parent to get and set the correct Path and update SortOrder if ParentId has changed if (((ICanBeDirty)entity).IsPropertyDirty("ParentId")) { @@ -370,5 +382,37 @@ namespace Umbraco.Core.Persistence.Repositories return new PropertyCollection(properties); } + + private string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0) + { + if (EnsureUniqueNaming == false) + return nodeName; + + var sql = new Sql(); + sql.Select("*") + .From() + .Where(x => x.NodeObjectType == NodeObjectTypeId && x.ParentId == parentId && x.Text.StartsWith(nodeName)); + + int uniqueNumber = 1; + var currentName = nodeName; + + var dtos = Database.Fetch(sql); + if (dtos.Any()) + { + var results = dtos.OrderBy(x => x.Text, new SimilarNodeNameComparer()); + foreach (var dto in results) + { + if (id != 0 && id == dto.NodeId) continue; + + if (dto.Text.ToLowerInvariant().Equals(currentName.ToLowerInvariant())) + { + currentName = nodeName + string.Format(" ({0})", uniqueNumber); + uniqueNumber++; + } + } + } + + return currentName; + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/SimilarNodeNameComparer.cs b/src/Umbraco.Core/Persistence/Repositories/SimilarNodeNameComparer.cs new file mode 100644 index 0000000000..734eecf1f9 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/SimilarNodeNameComparer.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.Persistence.Repositories +{ + /// + /// Comparer that takes into account the duplicate index of a node name + /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. + /// + internal class SimilarNodeNameComparer : IComparer + { + public int Compare(string x, string y) + { + if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) + { + if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) + { + int xDuplicateIndex = ExtractDuplicateIndex(x); + int yDuplicateIndex = ExtractDuplicateIndex(y); + + if (xDuplicateIndex != 0 && yDuplicateIndex != 0) + { + return xDuplicateIndex.CompareTo(yDuplicateIndex); + } + } + } + return String.Compare(x.ToLower(), y.ToLower(), StringComparison.Ordinal); + } + + private int ExtractDuplicateIndex(string text) + { + int index = 0; + + if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) + { + int startPos = text.LastIndexOf('(') + 1; + int length = text.Length - 1 - startPos; + + int.TryParse(text.Substring(startPos, length), out index); + } + + return index; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index 38189576a7..73c7b290f9 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -81,7 +81,7 @@ namespace Umbraco.Core.Persistence return new MediaRepository( uow, RuntimeCacheProvider.Current, - CreateMediaTypeRepository(uow)); + CreateMediaTypeRepository(uow)) { EnsureUniqueNaming = Umbraco.Core.Configuration.UmbracoSettings.EnsureUniqueNaming }; } public virtual IMediaTypeRepository CreateMediaTypeRepository(IDatabaseUnitOfWork uow) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 97c29aac50..9c97c3d453 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -497,6 +497,7 @@ + From b1285fa7e35c5e46c48b1509af8c5454b79e4039 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Thu, 4 Jul 2013 12:31:10 +0200 Subject: [PATCH 14/25] Add missing id to unique naming overload --- src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index 94b8a21859..e27fac1ba3 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -256,7 +256,7 @@ namespace Umbraco.Core.Persistence.Repositories ((Models.Media)entity).UpdatingEntity(); //Ensure unique name on the same level - entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name); + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id); //Look up parent to get and set the correct Path and update SortOrder if ParentId has changed if (((ICanBeDirty)entity).IsPropertyDirty("ParentId")) From 173d388c129e58b8546909b5161cad7df53f924f Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Thu, 4 Jul 2013 12:31:31 +0200 Subject: [PATCH 15/25] Fixes #U4-2450 --- src/Umbraco.Core/Services/ContentService.cs | 10 ++++------ src/Umbraco.Core/Services/MediaService.cs | 10 +++++----- src/umbraco.cms/businesslogic/media/Media.cs | 3 +-- src/umbraco.cms/businesslogic/web/Document.cs | 5 +---- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 1828d66daf..b3f8c9dec3 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -3,14 +3,12 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; -using System.Web; using System.Xml.Linq; using Umbraco.Core.Auditing; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Caching; @@ -88,7 +86,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this); - Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); + Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id); return content; } @@ -123,7 +121,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parent), this); - Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); + Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id); return content; } @@ -163,7 +161,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this); - Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); + Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id); return content; } @@ -203,7 +201,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parent), this); - Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); + Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id); return content; } diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 7a09e24b32..0e35802961 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -63,9 +63,9 @@ namespace Umbraco.Core.Services media.CreatorId = userId; - Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parentId), this); + Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parentId), this); - Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id); + Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id); return media; } @@ -98,7 +98,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parent), this); - Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id); + Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id); return media; } @@ -142,7 +142,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parentId), this); - Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id); + Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id); return media; } @@ -186,7 +186,7 @@ namespace Umbraco.Core.Services Created.RaiseEvent(new NewEventArgs(media, false, mediaTypeAlias, parent), this); - Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id); + Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id); return media; } diff --git a/src/umbraco.cms/businesslogic/media/Media.cs b/src/umbraco.cms/businesslogic/media/Media.cs index 252d8cd799..6dcff5792f 100644 --- a/src/umbraco.cms/businesslogic/media/Media.cs +++ b/src/umbraco.cms/businesslogic/media/Media.cs @@ -92,12 +92,11 @@ namespace umbraco.cms.businesslogic.media return null; } - var media = ApplicationContext.Current.Services.MediaService.CreateMedia(Name, ParentId, dct.Alias, u.Id); + var media = ApplicationContext.Current.Services.MediaService.CreateMediaWithIdentity(Name, ParentId, dct.Alias, u.Id); //The media object will only have the 'WasCancelled' flag set to 'True' if the 'Creating' event has been cancelled if (((Entity)media).WasCancelled) return null; - ApplicationContext.Current.Services.MediaService.Save(media); var tmp = new Media(media); tmp.OnNew(e); diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 6be26cfa77..2df9e19f37 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -306,14 +306,11 @@ namespace umbraco.cms.businesslogic.web } //Create a new IContent object based on the passed in DocumentType's alias, set the name and save it - IContent content = ApplicationContext.Current.Services.ContentService.CreateContent(Name, ParentId, dct.Alias, u.Id); + IContent content = ApplicationContext.Current.Services.ContentService.CreateContentWithIdentity(Name, ParentId, dct.Alias, u.Id); //The content object will only have the 'WasCancelled' flag set to 'True' if the 'Creating' event has been cancelled, so we return null. if (((Entity)content).WasCancelled) return null; - //don't raise events here (false), they will get raised with the d.Save() call. - ApplicationContext.Current.Services.ContentService.Save(content, u.Id, false); - //read the whole object from the db Document d = new Document(content); From 048480d5be9ff1fa6b6681608b5453169e8ab7ba Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Jul 2013 14:12:31 +1000 Subject: [PATCH 16/25] Fixes: #U4-2460 - UmbracoHelper.RenderTemplate will now execute the complete MVC cycle when rendering MVC templates whereas before it would only execute the view which means any actionfilters, etc... applied would never have fired (as well as other things) --- src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs | 13 +++++ .../Standalone/StandaloneHttpContext.cs | 52 ++++++++++++++++++- src/Umbraco.Web/Templates/TemplateRenderer.cs | 36 ++++++++++--- 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs index 1ace297bfd..649ac54f27 100644 --- a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs +++ b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; @@ -38,6 +40,15 @@ namespace Umbraco.Web.Mvc routeDef.Controller = controller; } + /// + /// This is used internally purely to render an Umbraco MVC template to string and shouldn't be used for anything else. + /// + internal void ExecuteUmbracoRequest() + { + StoreControllerInRouteDefinition(); + base.ProcessRequest(RequestContext.HttpContext); + } + protected override void ProcessRequest(HttpContextBase httpContext) { StoreControllerInRouteDefinition(); @@ -54,4 +65,6 @@ namespace Umbraco.Web.Mvc return base.BeginProcessRequest(httpContext, callback, state); } } + + } \ No newline at end of file diff --git a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs index 4cf64a8adf..55339e97b6 100644 --- a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs +++ b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; @@ -11,11 +13,59 @@ namespace Umbraco.Web.Standalone /// internal class StandaloneHttpContext : HttpContextBase { + private readonly string _url; + private readonly HttpSessionStateBase _session = new StandaloneHttpSessionState(); + private readonly HttpResponseBase _response; + private readonly HttpRequestBase _request = new StandaloneHttpRequest(); + private readonly TextWriter _writer = new StringWriter(); + private readonly IDictionary _items = new Dictionary(); + + public StandaloneHttpContext() + { + //create a custom response with a custom writer. + _response = new HttpResponseWrapper(new HttpResponse(_writer)); + } + + public StandaloneHttpContext(string url) + : this() + { + if (url == null) throw new ArgumentNullException("url"); + _url = url; + _request = new HttpRequestWrapper(new HttpRequest("", _url, "")); + } + + // fixme - what shall we implement here? + + public override IDictionary Items + { + get { return _items; } + } + + public override HttpSessionStateBase Session + { + get { return _session; } + } public override HttpRequestBase Request { - get { return null; } + get { return _request; } } + + public override HttpResponseBase Response + { + get { return _response; } + } + + } + + internal class StandaloneHttpSessionState : HttpSessionStateBase + { + + } + + internal class StandaloneHttpRequest : HttpRequestBase + { + } } diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index fe60c6959e..a13ed031f8 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -137,12 +137,9 @@ namespace Umbraco.Web.Templates requestContext.RouteData.Values.Add("controller", routeDef.ControllerName); //add the rest of the required route data routeHandler.SetupRouteDataForRequest(renderModel, requestContext, contentRequest); - //create and assign the controller context - routeDef.Controller.ControllerContext = new ControllerContext(requestContext, routeDef.Controller); - //render as string - var stringOutput = routeDef.Controller.RenderViewToString( - routeDef.ActionName, - renderModel); + + var stringOutput = RenderUmbracoRequestToString(requestContext); + sw.Write(stringOutput); break; case RenderingEngine.WebForms: @@ -157,6 +154,33 @@ namespace Umbraco.Web.Templates } + /// + /// This will execute the UmbracoMvcHandler for the request specified and get the string output. + /// + /// + /// Assumes the RequestContext is setup specifically to render an Umbraco view. + /// + /// + /// + /// To acheive this we temporarily change the output text writer of the current HttpResponse, then + /// execute the controller via the handler which innevitably writes the result to the text writer + /// that has been assigned to the response. Then we change the response textwriter back to the original + /// before continuing . + /// + private string RenderUmbracoRequestToString(RequestContext requestContext) + { + var currentWriter = requestContext.HttpContext.Response.Output; + var newWriter = new StringWriter(); + requestContext.HttpContext.Response.Output = newWriter; + + var handler = new UmbracoMvcHandler(requestContext); + handler.ExecuteUmbracoRequest(); + + //reset it + requestContext.HttpContext.Response.Output = currentWriter; + return newWriter.ToString(); + } + private void SetNewItemsOnContextObjects(PublishedContentRequest contentRequest) { // handlers like default.aspx will want it and most macros currently need it From 60805f91d6cfe5e9854c092c15e6555da3fa7ca1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Jul 2013 16:58:51 +1000 Subject: [PATCH 17/25] bit of code cleaning. --- src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../ActionHandlers/SimilarNodeNameComparer.cs | 46 ++++++++++++++ .../ActionHandlers/umbEnsureUniqueName.cs | 41 ------------- .../umbraco/create/content.ascx.cs | 60 +++++++------------ .../umbraco/create/contentTasks.cs | 28 ++++----- .../umbraco/dialogs/create.aspx.cs | 14 ++--- src/umbraco.cms/Actions/ActionNew.cs | 6 +- 7 files changed, 90 insertions(+), 106 deletions(-) create mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index ab431d6c84..d99c76a624 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -367,6 +367,7 @@ + ASPXCodeBehind diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs new file mode 100644 index 0000000000..148d395524 --- /dev/null +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace umbraco.ActionHandlers +{ + /// + /// Comparer that takes into account the duplicate index of a node name + /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. + /// + [Obsolete("This class is no longer used and will be removed from the codebase in future versions")] + public class SimilarNodeNameComparer : IComparer + { + public int Compare(string x, string y) + { + if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) + { + if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) + { + int xDuplicateIndex = ExtractDuplicateIndex(x); + int yDuplicateIndex = ExtractDuplicateIndex(y); + + if (xDuplicateIndex != 0 && yDuplicateIndex != 0) + { + return xDuplicateIndex.CompareTo(yDuplicateIndex); + } + } + } + return x.ToLower().CompareTo(y.ToLower()); + } + + private int ExtractDuplicateIndex(string text) + { + int index = 0; + + if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) + { + int startPos = text.LastIndexOf('(') + 1; + int length = text.Length - 1 - startPos; + + int.TryParse(text.Substring(startPos, length), out index); + } + + return index; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs index baacbff4f6..d5fab83940 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using Umbraco.Core.Logging; using umbraco.cms.businesslogic.web; @@ -89,44 +88,4 @@ namespace umbraco.ActionHandlers #endregion } - - /// - /// Comparer that takes into account the duplicate index of a node name - /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. - /// - public class SimilarNodeNameComparer : IComparer - { - public int Compare(string x, string y) - { - if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) - { - if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) - { - int xDuplicateIndex = ExtractDuplicateIndex(x); - int yDuplicateIndex = ExtractDuplicateIndex(y); - - if (xDuplicateIndex != 0 && yDuplicateIndex != 0) - { - return xDuplicateIndex.CompareTo(yDuplicateIndex); - } - } - } - return x.ToLower().CompareTo(y.ToLower()); - } - - private int ExtractDuplicateIndex(string text) - { - int index = 0; - - if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) - { - int startPos = text.LastIndexOf('(') + 1; - int length = text.Length - 1 - startPos; - - int.TryParse(text.Substring(startPos, length), out index); - } - - return index; - } - } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs index 14347b5c04..91b2a8c519 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs @@ -3,12 +3,12 @@ using System.Linq; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; +using Umbraco.Core.IO; using umbraco.cms.businesslogic.web; using umbraco.presentation.create; using Content=umbraco.cms.businesslogic.Content; using umbraco.cms.helpers; using umbraco.BasePages; -using umbraco.IO; namespace umbraco.cms.presentation.create.controls { @@ -19,48 +19,48 @@ namespace umbraco.cms.presentation.create.controls { protected void Page_Load(object sender, EventArgs e) { - if (!IsPostBack) + if (IsPostBack == false) { sbmt.Text = ui.Text("create"); - int NodeId = int.Parse(Request["nodeID"]); + var nodeId = int.Parse(Request["nodeID"]); - int[] allowedIds = new int[0]; - if (NodeId > 0) + var allowedIds = new int[0]; + if (nodeId > 0) { - Content c = new Document(NodeId); + var c = new Document(nodeId); allowedIds = c.ContentType.AllowedChildContentTypeIDs; } nodeType.Attributes.Add("onChange", "document.getElementById('typeDescription').innerHTML = typeInfo[this.selectedIndex];"); - int counter = 0; - bool typeInited = false; - StringBuilder js = new StringBuilder(); + var counter = 0; + var typeInited = false; + var js = new StringBuilder(); var documentTypeList = DocumentType.GetAllAsList().ToList(); - foreach (DocumentType dt in documentTypeList) + foreach (var dt in documentTypeList) { string docDescription = "No description available..."; - if (dt.Description != null && dt.Description != "") + if (string.IsNullOrEmpty(dt.Description) == false) docDescription = dt.Description; docDescription = "" + dt.Text + "
" + docDescription.Replace(Environment.NewLine, "
"); docDescription = docDescription.Replace("'", "\\'"); - string docImage = (dt.Thumbnail != "") ? dt.Thumbnail : "../nada.gif"; + var docImage = (dt.Thumbnail != "") ? dt.Thumbnail : "../nada.gif"; docImage = IOHelper.ResolveUrl( SystemDirectories.Umbraco ) + "/images/thumbnails/" + docImage; - ListItem li = new ListItem(); + var li = new ListItem(); li.Text = dt.Text; li.Value = dt.Id.ToString(); - if (NodeId > 0) + if (nodeId > 0) { - foreach (int i in allowedIds) if (i == dt.Id) + foreach (var i in allowedIds) if (i == dt.Id) { nodeType.Items.Add(li); js.Append("typeInfo[" + counter + "] = '

" + docDescription + "

'\n"); - if (!typeInited) + if (typeInited == false) { descr.Text = "

" + docDescription + "

"; @@ -76,7 +76,7 @@ namespace umbraco.cms.presentation.create.controls nodeType.Items.Add(li); js.Append("typeInfo[" + counter + "] = '

" + docDescription + "

'\n"); - if (!typeInited) + if (typeInited == false) { descr.Text = "

" + docDescription + "

'"; @@ -94,34 +94,14 @@ namespace umbraco.cms.presentation.create.controls } } - #region Web Form Designer generated code - - protected override void OnInit(EventArgs e) - { - // - // CODEGEN: This call is required by the ASP.NET Web Form Designer. - // - InitializeComponent(); - base.OnInit(e); - } - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - } - - #endregion - + protected void sbmt_Click(object sender, EventArgs e) { - doCreation(); + DoCreation(); } - private void doCreation() + private void DoCreation() { if (Page.IsValid) { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs index a0c6c616fb..45cc4a737c 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs @@ -13,14 +13,14 @@ namespace umbraco { private string _alias; - private int _parentID; - private int _typeID; - private int _userID; + private int _parentId; + private int _typeId; + private int _userId; private string _returnUrl = ""; public int UserId { - set { _userID = value; } + set { _userId = value; } } public string ReturnUrl @@ -30,8 +30,8 @@ namespace umbraco public int TypeID { - set { _typeID = value; } - get { return _typeID; } + set { _typeId = value; } + get { return _typeId; } } public string Alias @@ -44,18 +44,18 @@ namespace umbraco { set { - _parentID = value; + _parentId = value; } get { - return _parentID; + return _parentId; } } public bool Save() { - cms.businesslogic.web.DocumentType dt = new cms.businesslogic.web.DocumentType(TypeID); - cms.businesslogic.web.Document d = cms.businesslogic.web.Document.MakeNew(Alias, dt, BusinessLogic.User.GetUser(_userID), ParentID); + var dt = new cms.businesslogic.web.DocumentType(TypeID); + var d = cms.businesslogic.web.Document.MakeNew(Alias, dt, User.GetUser(_userId), ParentID); if (d == null) { //TODO: Slace - Fix this to use the language files @@ -71,13 +71,13 @@ namespace umbraco public bool Delete() { - cms.businesslogic.web.Document d = new cms.businesslogic.web.Document(ParentID); - - // Log - BusinessLogic.Log.Add(BusinessLogic.LogTypes.Delete, User.GetCurrent(), d.Id, ""); + var d = new cms.businesslogic.web.Document(ParentID); d.delete(); + // Log + Log.Add(LogTypes.Delete, User.GetCurrent(), d.Id, ""); + return true; } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs index ca384bd3af..7bc9354816 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs @@ -9,8 +9,8 @@ using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using System.Xml; +using Umbraco.Core.IO; using umbraco.cms.businesslogic; -using umbraco.IO; using umbraco.presentation; using umbraco.BusinessLogic.Actions; using umbraco.BasePages; @@ -44,19 +44,19 @@ namespace umbraco.dialogs if (helper.Request("app") == Constants.Applications.Media || CheckCreatePermissions(nodeId)) { //pane_chooseName.Text = ui.Text("create", "updateData", this.getUser()); - cms.businesslogic.CMSNode c = new cms.businesslogic.CMSNode(nodeId); + var c = new CMSNode(nodeId); path.Value = c.Path; pane_chooseNode.Visible = false; panel_buttons.Visible = false; pane_chooseName.Visible = true; - XmlDocument createDef = new XmlDocument(); - XmlTextReader defReader = new XmlTextReader(Server.MapPath(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/config/create/UI.xml")); + var createDef = new XmlDocument(); + var defReader = new XmlTextReader(Server.MapPath(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/config/create/UI.xml")); createDef.Load(defReader); defReader.Close(); // Find definition for current nodeType XmlNode def = createDef.SelectSingleNode("//nodeType [@alias = '" + Request.QueryString["app"] + "']"); - phCreate.Controls.Add(new UserControl().LoadControl(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + def.SelectSingleNode("./usercontrol").FirstChild.Value)); + phCreate.Controls.Add(new UserControl().LoadControl(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + def.SelectSingleNode("./usercontrol").FirstChild.Value)); } else { @@ -71,8 +71,8 @@ namespace umbraco.dialogs protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.Webservices) +"/cmsnode.asmx")); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.Webservices) +"/legacyAjaxCalls.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.WebServices) +"/cmsnode.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.WebServices) +"/legacyAjaxCalls.asmx")); } private bool CheckCreatePermissions(int nodeId) diff --git a/src/umbraco.cms/Actions/ActionNew.cs b/src/umbraco.cms/Actions/ActionNew.cs index ec07d8096a..ff17c91a0b 100644 --- a/src/umbraco.cms/Actions/ActionNew.cs +++ b/src/umbraco.cms/Actions/ActionNew.cs @@ -10,9 +10,7 @@ namespace umbraco.BusinessLogic.Actions public class ActionNew : IAction { //create singleton -#pragma warning disable 612,618 - private static readonly ActionNew m_instance = new ActionNew(); -#pragma warning restore 612,618 + private static readonly ActionNew InnerInstance = new ActionNew(); /// /// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons. @@ -24,7 +22,7 @@ namespace umbraco.BusinessLogic.Actions public static ActionNew Instance { - get { return m_instance; } + get { return InnerInstance; } } #region IAction Members From 93def731ef3ce8151b6aab37d922338c7d208054 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 5 Jul 2013 10:51:19 +0200 Subject: [PATCH 18/25] Fixes #U4-2466 --- .../umbraco_client/tags/css/jquery.tagsinput.css | 5 +++++ src/umbraco.controls/DatePicker/DateTimePicker.cs | 4 ---- src/umbraco.editorControls/tags/DataEditor.cs | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco_client/tags/css/jquery.tagsinput.css b/src/Umbraco.Web.UI/umbraco_client/tags/css/jquery.tagsinput.css index c595e249f9..3af1d36e55 100644 --- a/src/Umbraco.Web.UI/umbraco_client/tags/css/jquery.tagsinput.css +++ b/src/Umbraco.Web.UI/umbraco_client/tags/css/jquery.tagsinput.css @@ -1,3 +1,8 @@ +/* From jquery-ui.custom.css */ +.ui-autocomplete { position: absolute; cursor: default; } +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + div.tagsinput { border:1px solid #CCC; background: #FFF; padding:5px; width:300px; height:100px; overflow-y: auto;} div.tagsinput span.tag { border: 1px solid #a5d24a; -moz-border-radius:2px; -webkit-border-radius:2px; display: block; float: left; padding: 5px; text-decoration:none; background: #cde69c; color: #638421; margin-right: 5px; margin-bottom:5px;font-family: helvetica; font-size:13px;} div.tagsinput span.tag a { font-weight: bold; color: #82ad2b; text-decoration:none; font-size: 11px; } diff --git a/src/umbraco.controls/DatePicker/DateTimePicker.cs b/src/umbraco.controls/DatePicker/DateTimePicker.cs index 5c453649e1..4df20fbb9d 100644 --- a/src/umbraco.controls/DatePicker/DateTimePicker.cs +++ b/src/umbraco.controls/DatePicker/DateTimePicker.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using ClientDependency.Core; using System.Web.UI; using System.Web.UI.WebControls; -using umbraco.IO; using System.Web.UI.HtmlControls; namespace umbraco.uicontrols.DatePicker diff --git a/src/umbraco.editorControls/tags/DataEditor.cs b/src/umbraco.editorControls/tags/DataEditor.cs index 4281e1f12a..22c9fd423b 100644 --- a/src/umbraco.editorControls/tags/DataEditor.cs +++ b/src/umbraco.editorControls/tags/DataEditor.cs @@ -62,7 +62,6 @@ namespace umbraco.editorControls.tags base.OnInit(e); // register all dependencies - only registered once - ClientDependencyLoader.Instance.RegisterDependency("ui/ui-lightness/jquery-ui.custom.css", "UmbracoClient", ClientDependencyType.Css); ClientDependencyLoader.Instance.RegisterDependency("css/umbracoGui.css", "UmbracoRoot", ClientDependencyType.Css); ClientDependencyLoader.Instance.RegisterDependency("tags/css/jquery.tagsinput.css", "UmbracoClient", ClientDependencyType.Css); ClientDependencyLoader.Instance.RegisterDependency("tags/js/jquery.tagsinput.min.js", "UmbracoClient", ClientDependencyType.Javascript); From b7f6195791bacf4784a73cc76c6d76aa43b256e9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 8 Jul 2013 17:29:26 +1000 Subject: [PATCH 19/25] Started adding base PermissionsRepository for sub classes to use for assigning permissions, created a BulkImport extension methods for PetaPoco with tests since we'll be needing that for assigning permissions in a nice way. Wrote unit tests for all sql gen for permissions and assigning permissions. This all starts fixing #U4-2161 but there's still a bit more work to do. --- src/Umbraco.Core/Models/Membership/IUser.cs | 2 +- src/Umbraco.Core/Models/Membership/User.cs | 2 +- .../Persistence/Factories/UserFactory.cs | 4 +- .../Persistence/Mappers/UserMapper.cs | 2 +- src/Umbraco.Core/Persistence/PetaPoco.cs | 2 +- .../Persistence/PetaPocoExtensions.cs | 78 +++++++++- .../Repositories/ContentRepository.cs | 17 ++- .../Repositories/PermissionRepository.cs | 135 ++++++++++++++++++ .../Repositories/UserRepository.cs | 7 +- .../Repositories/VersionableRepositoryBase.cs | 2 +- .../Persistence/UmbracoDatabase.cs | 5 +- src/Umbraco.Core/Services/UserService.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Persistence/PetaPocoExtensionsTest.cs | 85 +++++++++++ .../Persistence/Querying/PetaPocoSqlTests.cs | 23 +++ .../Repositories/ContentRepositoryTest.cs | 38 +++++ .../Repositories/UserRepositoryTest.cs | 34 ++++- .../Services/UserServiceTests.cs | 6 +- .../TestHelpers/Entities/MockedUser.cs | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + src/umbraco.businesslogic/User.cs | 15 +- 21 files changed, 432 insertions(+), 31 deletions(-) create mode 100644 src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs create mode 100644 src/Umbraco.Tests/Persistence/PetaPocoExtensionsTest.cs diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index 25a4133eb2..97e7e4132f 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Models.Membership bool NoConsole { get; set; } IUserType UserType { get; } - string Permissions { get; set; } + string DefaultPermissions { get; set; } } internal interface IUserProfile : IProfile diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index d6b71135ef..ddcc28cccb 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -91,7 +91,7 @@ namespace Umbraco.Core.Models.Membership [DataMember] public string Language { get; set; } [DataMember] - public string Permissions { get; set; } + public string DefaultPermissions { get; set; } [DataMember] public bool DefaultToLiveEditing { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs index 6d38db9739..0a046ca7a0 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs @@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Factories Language = dto.UserLanguage, DefaultToLiveEditing = dto.DefaultToLiveEditing, NoConsole = dto.NoConsole, - Permissions = dto.DefaultPermissions + DefaultPermissions = dto.DefaultPermissions }; foreach (var app in dto.User2AppDtos) @@ -62,7 +62,7 @@ namespace Umbraco.Core.Persistence.Factories UserLanguage = entity.Language, UserName = entity.Name, Type = short.Parse(entity.UserType.Id.ToString()), - DefaultPermissions = entity.Permissions, + DefaultPermissions = entity.DefaultPermissions, User2AppDtos = new List() }; diff --git a/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs b/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs index 1a7add097a..5e2947c3a7 100644 --- a/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs @@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Username, dto => dto.Login); CacheMap(src => src.Password, dto => dto.Password); CacheMap(src => src.Name, dto => dto.UserName); - CacheMap(src => src.Permissions, dto => dto.DefaultPermissions); + CacheMap(src => src.DefaultPermissions, dto => dto.DefaultPermissions); CacheMap(src => src.StartMediaId, dto => dto.MediaStartId); CacheMap(src => src.StartContentId, dto => dto.ContentStartId); CacheMap(src => src.DefaultToLiveEditing, dto => dto.DefaultToLiveEditing); diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs index 269fea5f9a..d8507ac681 100644 --- a/src/Umbraco.Core/Persistence/PetaPoco.cs +++ b/src/Umbraco.Core/Persistence/PetaPoco.cs @@ -384,7 +384,7 @@ namespace Umbraco.Core.Persistence } // Add a parameter to a DB command - void AddParam(IDbCommand cmd, object item, string ParameterPrefix) + internal void AddParam(IDbCommand cmd, object item, string ParameterPrefix) { // Convert value to from poco type to db type if (Database.Mapper != null && item!=null) diff --git a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs index 85ab884857..6faf4d637a 100644 --- a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs +++ b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Data; using System.Linq; using Umbraco.Core.Logging; using Umbraco.Core.Models.Rdbms; @@ -28,6 +30,76 @@ namespace Umbraco.Core.Persistence CreateTable(db, overwrite, tableType); } + public static void BulkInsertRecords(this Database db, IEnumerable collection) + { + using (var tr = db.GetTransaction()) + { + try + { + if (SqlSyntaxContext.SqlSyntaxProvider is SqlCeSyntaxProvider) + { + //SqlCe doesn't support bulk insert statements! + + foreach (var poco in collection) + { + db.Insert(poco); + } + + } + else + { + string sql; + using (var cmd = db.GenerateBulkInsertCommand(collection, db.Connection, out sql)) + { + cmd.CommandText = sql; + cmd.ExecuteNonQuery(); + } + } + + tr.Complete(); + } + catch + { + tr.Dispose(); + throw; + } + } + } + + internal static IDbCommand GenerateBulkInsertCommand(this Database db, IEnumerable collection, IDbConnection connection, out string sql) + { + var pd = Database.PocoData.ForType(typeof(T)); + var tableName = db.EscapeTableName(pd.TableInfo.TableName); + + //get all columns but not the primary key if it is auto-incremental + var cols = string.Join(", ", ( + from c in pd.Columns + where c.Value.ResultColumn == false + select tableName + "." + db.EscapeSqlIdentifier(c.Key)) + .ToArray()); + + var cmd = db.CreateCommand(connection, ""); + + var pocoValues = new List(); + var index = 0; + foreach (var poco in collection) + { + var values = new List(); + foreach (var i in pd.Columns) + { + //if (pd.TableInfo.AutoIncrement && i.Key == pd.TableInfo.PrimaryKey) + //{ + // continue; + //} + values.Add(string.Format("{0}{1}", "@", index++)); + db.AddParam(cmd, i.Value.GetValue(poco), "@"); + } + pocoValues.Add("(" + string.Join(",", values.ToArray()) + ")"); + } + sql = string.Format("INSERT INTO {0} ({1}) VALUES {2}", tableName, cols, string.Join(", ", pocoValues)); + return cmd; + } + public static void CreateTable(this Database db, bool overwrite, Type modelType) { var tableDefinition = DefinitionFactory.GetTableDefinition(modelType); @@ -67,7 +139,7 @@ namespace Umbraco.Core.Persistence //Turn on identity insert if db provider is not mysql if (SqlSyntaxContext.SqlSyntaxProvider.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity)) db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName)))); - + //Call the NewTable-event to trigger the insert of base/default data NewTable(tableName, db, e); @@ -106,7 +178,7 @@ namespace Umbraco.Core.Persistence public static void DropTable(this Database db) where T : new() { - Type type = typeof (T); + Type type = typeof(T); var tableNameAttribute = type.FirstAttribute(); if (tableNameAttribute == null) throw new Exception( @@ -184,5 +256,5 @@ namespace Umbraco.Core.Persistence } } - internal class TableCreationEventArgs : System.ComponentModel.CancelEventArgs{} + internal class TableCreationEventArgs : System.ComponentModel.CancelEventArgs { } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 58b07e1583..a2b720d06d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -206,7 +206,7 @@ namespace Umbraco.Core.Persistence.Repositories nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture)); nodeDto.SortOrder = sortOrder; var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto); - + //Update with new correct path nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); Database.Update(nodeDto); @@ -217,6 +217,21 @@ namespace Umbraco.Core.Persistence.Repositories entity.SortOrder = sortOrder; entity.Level = level; + + //Assign the same permissions to it as the parent node + // http://issues.umbraco.org/issue/U4-2161 + var parentPermissions = GetPermissionsForEntity(entity.ParentId).ToArray(); + //if there are parent permissions then assign them, otherwise leave null and permissions will become the + // user's default permissions. + if (parentPermissions.Any()) + { + //group by the unique permission and assign then for the users of that permission set. + foreach (var assignedPermission in parentPermissions.GroupBy(x => x.Permission)) + { + AssignEntityPermissions(entity, assignedPermission.Key, assignedPermission.Select(x => (object)x.UserId)); + } + } + //Create the Content specific data - cmsContent var contentDto = dto.ContentVersionDto.ContentDto; contentDto.NodeId = nodeDto.NodeId; diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs new file mode 100644 index 0000000000..88087c7999 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Text; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.Caching; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Persistence.UnitOfWork; + +namespace Umbraco.Core.Persistence.Repositories +{ + /// + /// A repository that exposes functionality to modify assigned permissions to a node + /// + /// + /// + internal abstract class PermissionRepository : PetaPocoRepositoryBase + where TEntity : class, IAggregateRoot + { + protected PermissionRepository(IDatabaseUnitOfWork work) + : base(work) + { + } + + protected PermissionRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache) + : base(work, cache) + { + } + + protected internal IEnumerable GetPermissionsForEntity(int entityId) + { + var sql = new Sql(); + sql.Select("*") + .From() + .Where(dto => dto.NodeId == entityId); + return Database.Fetch(sql); + } + + /// + /// Assigns permissions to an entity for multiple users + /// + /// + /// + /// + protected internal void AssignEntityPermissions(TEntity entity, string permissions, IEnumerable userIds) + { + var actions = userIds.Select(id => new User2NodePermissionDto + { + NodeId = entity.Id, + Permission = permissions, + UserId = (int)id + }); + + Database.BulkInsertRecords(actions); + } + + /// + /// Replace permissions for an entity for multiple users + /// + /// + /// + /// + protected internal void ReplaceEntityPermissions(TEntity entity, string permissions, IEnumerable userIds) + { + Database.Update( + GenerateReplaceEntityPermissionsSql(entity.Id, permissions, userIds.ToArray())); + } + + /// + /// An overload to replace entity permissions and all replace all descendant permissions + /// + /// + /// + /// + /// A callback to get the descendant Ids of the current entity + /// + /// + protected internal void ReplaceEntityPermissions(TEntity entity, string permissions, Func> getDescendantIds, IEnumerable userIds) + { + Database.Update( + GenerateReplaceEntityPermissionsSql( + new[] {entity.Id}.Concat(getDescendantIds(entity)).ToArray(), + permissions, + userIds.ToArray())); + } + + internal static string GenerateReplaceEntityPermissionsSql(int entityId, string permissions, object[] userIds) + { + return GenerateReplaceEntityPermissionsSql(new[] {entityId}, permissions, userIds); + } + + internal static string GenerateReplaceEntityPermissionsSql(int[] entityIds, string permissions, object[] userIds) + { + //create the "SET" clause of the update statement + var sqlSet = string.Format("SET {0}={1}", + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("permission"), + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(permissions)); + + //build the nodeIds part of the where clause + var sqlNodeWhere = BuildOrClause(entityIds, "nodeId"); + + //build up the userIds part of the where clause + var userWhereBuilder = BuildOrClause(userIds, "userId"); + + var sqlWhere = new Sql(); + sqlWhere.Where(string.Format("{0} AND {1}", sqlNodeWhere, userWhereBuilder)); + + return string.Format("{0} {1}", sqlSet, sqlWhere.SQL); + } + + private static string BuildOrClause(IEnumerable ids, string colName) + { + var asArray = ids.ToArray(); + var userWhereBuilder = new StringBuilder(); + userWhereBuilder.Append("("); + for (var index = 0; index < asArray.Length; index++) + { + var userId = asArray[index]; + userWhereBuilder.Append(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(colName)); + userWhereBuilder.Append("="); + userWhereBuilder.Append(userId); + if (index < asArray.Length - 1) + { + userWhereBuilder.Append(" OR "); + } + } + userWhereBuilder.Append(")"); + return userWhereBuilder.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs index cd10d4e6a4..0acad10383 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Represents the UserRepository for doing CRUD operations for /// - internal class UserRepository : PetaPocoRepositoryBase, IUserRepository + internal class UserRepository : PermissionRepository, IUserRepository { private readonly IUserTypeRepository _userTypeRepository; @@ -122,9 +122,12 @@ namespace Umbraco.Core.Persistence.Repositories } protected override IEnumerable GetDeleteClauses() - { + { var list = new List { + "DELETE FROM umbracoUser2NodePermission WHERE userId = @Id", + "DELETE FROM umbracoUser2NodeNotify WHERE userId = @Id", + "DELETE FROM umbracoUserLogins WHERE userId = @Id", "DELETE FROM umbracoUser2app WHERE " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("user") + "=@Id", "DELETE FROM umbracoUser WHERE id = @Id" }; diff --git a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs index 3a9b5041eb..0ed84582fa 100644 --- a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Persistence.Repositories { - internal abstract class VersionableRepositoryBase : PetaPocoRepositoryBase + internal abstract class VersionableRepositoryBase : PermissionRepository where TEntity : class, IAggregateRoot { protected VersionableRepositoryBase(IDatabaseUnitOfWork work) : base(work) diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index e69ef4cca2..522e0b4173 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Linq; using StackExchange.Profiling; using Umbraco.Core.Logging; @@ -46,8 +48,7 @@ namespace Umbraco.Core.Persistence // wrap the connection with a profiling connection that tracks timings return new StackExchange.Profiling.Data.ProfiledDbConnection(connection as DbConnection, MiniProfiler.Current); } - - + public override void OnException(Exception x) { LogHelper.Info(x.StackTrace); diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index f7bbe244bb..e451d3aa05 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -164,7 +164,7 @@ namespace Umbraco.Core.Services Language = Umbraco.Core.Configuration.GlobalSettings.DefaultUILanguage, Name = name, Password = password, - Permissions = userType.Permissions, + DefaultPermissions = userType.Permissions, Username = login, StartContentId = -1, StartMediaId = -1, diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9c97c3d453..ccc361e3f7 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -491,6 +491,7 @@ + diff --git a/src/Umbraco.Tests/Persistence/PetaPocoExtensionsTest.cs b/src/Umbraco.Tests/Persistence/PetaPocoExtensionsTest.cs new file mode 100644 index 0000000000..1cf6aff7b0 --- /dev/null +++ b/src/Umbraco.Tests/Persistence/PetaPocoExtensionsTest.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence; +using Umbraco.Tests.TestHelpers; + +namespace Umbraco.Tests.Persistence +{ + [TestFixture] + public class PetaPocoExtensionsTest : BaseDatabaseFactoryTest + { + [SetUp] + public override void Initialize() + { + base.Initialize(); + } + + [TearDown] + public override void TearDown() + { + base.TearDown(); + } + + [Test] + public void Can_Bulk_Insert() + { + // Arrange + var db = DatabaseContext.Database; + + var servers = new List(); + for (var i = 0; i < 1000; i++) + { + servers.Add(new ServerRegistrationDto + { + Address = "address" + i, + ComputerName = "computer" + i, + DateRegistered = DateTime.Now, + IsActive = true, + LastNotified = DateTime.Now + }); + } + + // Act + using (DisposableTimer.TraceDuration("starting insert", "finished insert")) + { + db.BulkInsertRecords(servers); + } + + // Assert + Assert.That(db.ExecuteScalar("SELECT COUNT(*) FROM umbracoServer"), Is.EqualTo(1000)); + } + + [Test] + public void Generate_Bulk_Import_Sql() + { + // Arrange + var db = DatabaseContext.Database; + + var servers = new List(); + for (var i = 0; i < 2; i++) + { + servers.Add(new ServerRegistrationDto + { + Address = "address" + i, + ComputerName = "computer" + i, + DateRegistered = DateTime.Now, + IsActive = true, + LastNotified = DateTime.Now + }); + } + db.OpenSharedConnection(); + + // Act + string sql; + db.GenerateBulkInsertCommand(servers, db.Connection, out sql); + db.CloseSharedConnection(); + + // Assert + Assert.That(sql, + Is.EqualTo("INSERT INTO [umbracoServer] ([umbracoServer].[address], [umbracoServer].[computerName], [umbracoServer].[registeredDate], [umbracoServer].[lastNotifiedDate], [umbracoServer].[isActive]) VALUES (@0,@1,@2,@3,@4), (@5,@6,@7,@8,@9)")); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs index 4c71c072c7..3ee82a820e 100644 --- a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs @@ -1,7 +1,10 @@ using System; using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Repositories; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Persistence.Querying @@ -9,6 +12,26 @@ namespace Umbraco.Tests.Persistence.Querying [TestFixture] public class PetaPocoSqlTests : BaseUsingSqlCeSyntax { + [Test] + public void Generate_Replace_Entity_Permissions_Test() + { + // Act + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, "abcd", new object[] {10, 11, 12}); + + // Assert + Assert.AreEqual(@"SET [permission]='abcd' WHERE (([nodeId]=123) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); + } + + [Test] + public void Generate_Replace_Entity_Permissions_With_Descendants_Test() + { + // Act + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] {123, 456}, "abcd", new object[] {10, 11, 12}); + + // Assert + Assert.AreEqual(@"SET [permission]='abcd' WHERE (([nodeId]=123 OR [nodeId]=456) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); + } + [Test] public void Can_Select_From_With_Type() { diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index b7717c6a23..0fb31e831c 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Querying; @@ -32,6 +34,42 @@ namespace Umbraco.Tests.Persistence.Repositories base.TearDown(); } + [Test] + public void Ensures_Permissions_Are_Set_If_Parent_Entity_Permissions_Exist() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + var contentTypeRepository = RepositoryResolver.Current.ResolveByType(unitOfWork); + var repository = (ContentRepository)RepositoryResolver.Current.ResolveByType(unitOfWork); + + var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); + contentType.AllowedContentTypes = new List + { + new ContentTypeSort + { + Alias = contentType.Alias, + Id = new Lazy(() => contentType.Id), + SortOrder = 0 + } + }; + var parentPage = MockedContent.CreateSimpleContent(contentType); + contentTypeRepository.AddOrUpdate(contentType); + repository.AddOrUpdate(parentPage); + unitOfWork.Commit(); + + // Act + repository.AssignEntityPermissions(parentPage, "ABCD", new object[] {0}); + var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage); + repository.AddOrUpdate(childPage); + unitOfWork.Commit(); + + // Assert + var permissions = repository.GetPermissionsForEntity(childPage.Id); + Assert.AreEqual(1, permissions.Count()); + Assert.AreEqual("ABCD", permissions.Single().Permission); + } + [Test] public void Can_Instantiate_Repository() { diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 76d21e1d56..a341a5cc74 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -115,7 +115,7 @@ namespace Umbraco.Tests.Persistence.Repositories var resolved = repository.Get((int)user.Id); resolved.Name = "New Name"; - resolved.Permissions = "ZYX"; + resolved.DefaultPermissions = "ZYX"; resolved.Language = "fr"; resolved.IsApproved = false; resolved.Password = "new"; @@ -134,7 +134,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id)); Assert.That(updatedItem.Name, Is.EqualTo(resolved.Name)); - Assert.That(updatedItem.Permissions, Is.EqualTo(resolved.Permissions)); + Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(resolved.DefaultPermissions)); Assert.That(updatedItem.Language, Is.EqualTo(resolved.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(resolved.IsApproved)); Assert.That(updatedItem.Password, Is.EqualTo(resolved.Password)); @@ -173,6 +173,32 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(resolved, Is.Null); } + //[Test] + //public void Can_Perform_Delete_On_UserRepository_With_Permissions_Assigned() + //{ + // // Arrange + // var provider = new PetaPocoUnitOfWorkProvider(); + // var unitOfWork = provider.GetUnitOfWork(); + // var repository = RepositoryResolver.Current.ResolveByType(unitOfWork); + + // var user = MockedUser.CreateUser(CreateAndCommitUserType()); + // //repository.AssignPermissions() + + // // Act + // repository.AddOrUpdate(user); + // unitOfWork.Commit(); + // var id = user.Id; + + // var repository2 = RepositoryResolver.Current.ResolveByType(unitOfWork); + // repository2.Delete(user); + // unitOfWork.Commit(); + + // var resolved = repository2.Get((int)id); + + // // Assert + // Assert.That(resolved, Is.Null); + //} + [Test] public void Can_Perform_Get_On_UserRepository() { @@ -190,7 +216,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert AssertPropertyValues(updatedItem, user); } - + [Test] public void Can_Perform_GetByQuery_On_UserRepository() { @@ -405,7 +431,7 @@ namespace Umbraco.Tests.Persistence.Repositories { Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id)); Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name)); - Assert.That(updatedItem.Permissions, Is.EqualTo(originalUser.Permissions)); + Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(originalUser.DefaultPermissions)); Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); Assert.That(updatedItem.Password, Is.EqualTo(originalUser.Password)); diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs index 6da5002436..b8cc7f6225 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests/Services/UserServiceTests.cs @@ -39,7 +39,7 @@ namespace Umbraco.Tests.Services Assert.That(membershipUser.HasIdentity, Is.True); IUser user = membershipUser as User; Assert.That(user, Is.Not.Null); - Assert.That(user.Permissions, Is.EqualTo(userType.Permissions)); + Assert.That(user.DefaultPermissions, Is.EqualTo(userType.Permissions)); } [Test] @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Services Assert.That(membershipUser.Password, Is.EqualTo(encodedPassword)); IUser user = membershipUser as User; Assert.That(user, Is.Not.Null); - Assert.That(user.Permissions, Is.EqualTo(userType.Permissions)); + Assert.That(user.DefaultPermissions, Is.EqualTo(userType.Permissions)); } [Test] @@ -140,7 +140,7 @@ namespace Umbraco.Tests.Services Assert.IsNotNull(updatedItem); Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id)); Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name)); - Assert.That(updatedItem.Permissions, Is.EqualTo(originalUser.Permissions)); + Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(originalUser.DefaultPermissions)); Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); Assert.That(updatedItem.Password, Is.EqualTo(originalUser.Password)); diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs index 19e0148383..7df112515d 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs @@ -19,7 +19,7 @@ namespace Umbraco.Tests.TestHelpers.Entities Name = "TestUser" + suffix, Password = "testing", NoConsole = false, - Permissions = "ABC", + DefaultPermissions = "ABC", StartContentId = -1, StartMediaId = -1, DefaultToLiveEditing = false, diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e4d21a8039..37b33cf460 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -185,6 +185,7 @@ + diff --git a/src/umbraco.businesslogic/User.cs b/src/umbraco.businesslogic/User.cs index ae5c0202ab..3ee8608da0 100644 --- a/src/umbraco.businesslogic/User.cs +++ b/src/umbraco.businesslogic/User.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; using umbraco.DataLayer; using System.Collections.Generic; @@ -667,7 +668,7 @@ namespace umbraco.BusinessLogic { if (!_isInitialized) setupUser(_id); - string cruds = UserType.DefaultPermissions; + string defaultPermissions = UserType.DefaultPermissions; if (!_crudsInitialized) initCruds(); @@ -681,16 +682,16 @@ namespace umbraco.BusinessLogic } // exception to everything. If default cruds is empty and we're on root node; allow browse of root node - if (String.IsNullOrEmpty(cruds) && Path == "-1") - cruds = "F"; + if (String.IsNullOrEmpty(defaultPermissions) && Path == "-1") + defaultPermissions = "F"; // else return default user type cruds - return cruds; + return defaultPermissions; } /// /// Initializes the user node permissions - /// + /// public void initCruds() { if (!_isInitialized) @@ -904,7 +905,7 @@ namespace umbraco.BusinessLogic public void FlushFromCache() { OnFlushingFromCache(EventArgs.Empty); - ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("UmbracoUser{0}", Id.ToString())); + ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserCacheKey, Id.ToString())); } /// @@ -915,7 +916,7 @@ namespace umbraco.BusinessLogic public static User GetUser(int id) { return ApplicationContext.Current.ApplicationCache.GetCacheItem( - string.Format("UmbracoUser{0}", id.ToString()), () => + string.Format("{0}{1}", CacheKeys.UserCacheKey, id.ToString()), () => { try { From 3c4cf56309ac02423ca7ef71ad0d2d78abe9c32a Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 8 Jul 2013 18:47:53 +1000 Subject: [PATCH 20/25] Fixes: #U4-2475 --- .../Cache/RuntimeCacheProviderBase.cs | 2 +- .../umbraco/dialogs/moveOrCopy.aspx.cs | 34 +++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs b/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs index 9dddb4c576..d88a3922bb 100644 --- a/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs +++ b/src/Umbraco.Core/Cache/RuntimeCacheProviderBase.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Cache /// An abstract class for implementing a runtime cache provider /// /// - /// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC... + /// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, REQUEST CACHE, ETC... /// internal abstract class RuntimeCacheProviderBase : CacheProviderBase { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs index ba48e944fa..2e804cee13 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs @@ -217,23 +217,35 @@ namespace umbraco.dialogs var nodeAllowed = false; IContentBase currContent; - IContentBase parentContent; - IContentTypeBase parentContentType; + IContentBase parentContent = null; + IContentTypeBase parentContentType = null; if (CurrentApp == "content") { currContent = Services.ContentService.GetById(Request.GetItemAs("id")); - parentContent = Services.ContentService.GetById(Request.GetItemAs("copyTo")); - parentContentType = Services.ContentTypeService.GetContentType(parentContent.ContentTypeId); + if (Request.GetItemAs("copyTo") != -1) + { + parentContent = Services.ContentService.GetById(Request.GetItemAs("copyTo")); + if (parentContent != null) + { + parentContentType = Services.ContentTypeService.GetContentType(parentContent.ContentTypeId); + } + } } else { currContent = Services.MediaService.GetById(Request.GetItemAs("id")); - parentContent = Services.MediaService.GetById(Request.GetItemAs("copyTo")); - parentContentType = Services.ContentTypeService.GetMediaType(parentContent.ContentTypeId); + if (Request.GetItemAs("copyTo") != -1) + { + parentContent = Services.MediaService.GetById(Request.GetItemAs("copyTo")); + if (parentContent != null) + { + parentContentType = Services.ContentTypeService.GetMediaType(parentContent.ContentTypeId); + } + } } // Check on contenttypes - if (Request.GetItemAs("copyTo") == -1) + if (parentContentType == null) { nodeAllowed = true; } @@ -268,7 +280,7 @@ namespace umbraco.dialogs pane_form_notice.Visible = false; panel_buttons.Visible = false; - var newNodeCaption = Request.GetItemAs("copyTo") == -1 + var newNodeCaption = parentContent == null ? ui.Text(CurrentApp) : parentContent.Name; @@ -290,19 +302,19 @@ namespace umbraco.dialogs feedback.type = uicontrols.Feedback.feedbacktype.success; // refresh tree - ClientTools.MoveNode(currContent.Id.ToString(), parentContent.Path); + ClientTools.MoveNode(currContent.Id.ToString(), currContent.Path); } else { //NOTE: We ONLY support Copy on content not media for some reason. - Services.ContentService.Copy((IContent)currContent, Request.GetItemAs("copyTo"), RelateDocuments.Checked, getUser().Id); + var newContent = Services.ContentService.Copy((IContent)currContent, Request.GetItemAs("copyTo"), RelateDocuments.Checked, getUser().Id); feedback.Text = ui.Text("moveOrCopy", "copyDone", nodes, getUser()) + "

" + ui.Text("closeThisWindow") + ""; feedback.type = uicontrols.Feedback.feedbacktype.success; // refresh tree - ClientTools.CopyNode(currContent.Id.ToString(), parentContent.Path); + ClientTools.CopyNode(currContent.Id.ToString(), newContent.Path); } } } From 90b94f6ffbb299b22a332a0a5e254aaf0a60ca4f Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 8 Jul 2013 18:58:38 +1000 Subject: [PATCH 21/25] Fixes: #U4-2476 --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 1 + .../umbraco/config/lang/en_us.xml | 1 + .../umbraco/dialogs/moveOrCopy.aspx.cs | 17 ++++++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index e895731f4b..f331e88d9b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -548,6 +548,7 @@ To manage your website, simply open the umbraco back office and start adding con No node selected yet, please select a node in the list above before clicking 'ok' The current node is not allowed under the chosen node because of its type The current node cannot be moved to one of its subpages + The current node cannot exist at the root The action isn't allowed since you have insufficient permissions on 1 or more child documents. Relate copied items to original 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 a3e66517da..2723e209f7 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -535,6 +535,7 @@ To manage your website, simply open the umbraco back office and start adding con No node selected yet, please select a node in the list above before clicking 'ok' The current node is not allowed under the chosen node because of its type The current node cannot be moved to one of its subpages + The current node cannot exist at the root The action isn't allowed since you have insufficient permissions on 1 or more child documents. Relate copied items to original diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs index 2e804cee13..3cb48ce274 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs @@ -247,7 +247,22 @@ namespace umbraco.dialogs // Check on contenttypes if (parentContentType == null) { - nodeAllowed = true; + //check if this is allowed at root + IContentTypeBase currContentType; + if (CurrentApp == "content") + { + currContentType = Services.ContentTypeService.GetContentType(currContent.ContentTypeId); + } + else + { + currContentType = Services.ContentTypeService.GetMediaType(currContent.ContentTypeId); + } + nodeAllowed = currContentType.AllowedAsRoot; + if (!nodeAllowed) + { + feedback.Text = ui.Text("moveOrCopy", "notAllowedAtRoot", UmbracoUser); + feedback.type = uicontrols.Feedback.feedbacktype.error; + } } else { From b91d0bb117b9ee343b7114e5c43e464d26d8f91e Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 9 Jul 2013 10:08:31 +1000 Subject: [PATCH 22/25] Updates ContentRepository to bulk insert all parent permissions at once (overload to the AssignEntityPermissions method) --- .../Repositories/ContentRepository.cs | 8 +++----- .../Repositories/PermissionRepository.cs | 19 +++++++++++++++++++ .../Persistence/Querying/PetaPocoSqlTests.cs | 8 ++++---- .../Repositories/ContentRepositoryTest.cs | 4 ++-- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index a2b720d06d..93179f7e91 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -225,11 +225,9 @@ namespace Umbraco.Core.Persistence.Repositories // user's default permissions. if (parentPermissions.Any()) { - //group by the unique permission and assign then for the users of that permission set. - foreach (var assignedPermission in parentPermissions.GroupBy(x => x.Permission)) - { - AssignEntityPermissions(entity, assignedPermission.Key, assignedPermission.Select(x => (object)x.UserId)); - } + var userPermissions = parentPermissions.ToDictionary( + permissionDto => (object) permissionDto.UserId, permissionDto => permissionDto.Permission); + AssignEntityPermissions(entity, userPermissions); } //Create the Content specific data - cmsContent diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs index 88087c7999..0bf6a6eeb8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -58,6 +58,25 @@ namespace Umbraco.Core.Persistence.Repositories Database.BulkInsertRecords(actions); } + ///

+ /// Assigns permissions to an entity for multiple users/permission entries + /// + /// + /// + /// A key/value pair list containing a userId and a permission to assign + /// + protected internal void AssignEntityPermissions(TEntity entity, IEnumerable> userPermissions) + { + var actions = userPermissions.Select(p => new User2NodePermissionDto + { + NodeId = entity.Id, + Permission = p.Value, + UserId = (int)p.Key + }); + + Database.BulkInsertRecords(actions); + } + /// /// Replace permissions for an entity for multiple users /// diff --git a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs index 3ee82a820e..8494ec7c8c 100644 --- a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs @@ -16,20 +16,20 @@ namespace Umbraco.Tests.Persistence.Querying public void Generate_Replace_Entity_Permissions_Test() { // Act - var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, "abcd", new object[] {10, 11, 12}); + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, "A", new object[] {10, 11, 12}); // Assert - Assert.AreEqual(@"SET [permission]='abcd' WHERE (([nodeId]=123) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); + Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); } [Test] public void Generate_Replace_Entity_Permissions_With_Descendants_Test() { // Act - var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] {123, 456}, "abcd", new object[] {10, 11, 12}); + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] {123, 456}, "A", new object[] {10, 11, 12}); // Assert - Assert.AreEqual(@"SET [permission]='abcd' WHERE (([nodeId]=123 OR [nodeId]=456) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); + Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123 OR [nodeId]=456) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); } [Test] diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index 0fb31e831c..973000b9ca 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -59,7 +59,7 @@ namespace Umbraco.Tests.Persistence.Repositories unitOfWork.Commit(); // Act - repository.AssignEntityPermissions(parentPage, "ABCD", new object[] {0}); + repository.AssignEntityPermissions(parentPage, "A", new object[] {0}); var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage); repository.AddOrUpdate(childPage); unitOfWork.Commit(); @@ -67,7 +67,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert var permissions = repository.GetPermissionsForEntity(childPage.Id); Assert.AreEqual(1, permissions.Count()); - Assert.AreEqual("ABCD", permissions.Single().Permission); + Assert.AreEqual("A", permissions.Single().Permission); } [Test] From 868edee5e647f6210e0a2507e615a93a2671f251 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 9 Jul 2013 11:47:46 +1000 Subject: [PATCH 23/25] Fixes: #U4-2161 - permissions inheritance. Fixes up how user permissions cache is invalidated and looked up (it is now lazy and not forced). User permissions are also cached as a low priority for now and only for 20 mins based on #U4-2474. --- src/Umbraco.Core/Cache/CacheKeys.cs | 1 + src/Umbraco.Core/Models/Content.cs | 19 +++++- .../Repositories/ContentRepository.cs | 13 +++- .../Cache/CacheRefresherEventHandler.cs | 49 ++++++++++++-- src/Umbraco.Web/Cache/DistributedCache.cs | 1 + .../Cache/DistributedCacheExtensions.cs | 17 +++++ src/Umbraco.Web/Cache/UserCacheRefresher.cs | 2 + .../Cache/UserPermissionsCacheRefresher.cs | 47 ++++++++++++++ .../Publishing/UpdateCacheAfterPublish.cs | 2 + .../Publishing/UpdateCacheAfterUnPublish.cs | 2 + src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../umbraco/dialogs/cruds.aspx.cs | 14 ---- src/umbraco.businesslogic/User.cs | 64 ++++++++++--------- 13 files changed, 179 insertions(+), 53 deletions(-) create mode 100644 src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 1c89d7662f..54f9ab4832 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -31,6 +31,7 @@ namespace Umbraco.Core.Cache public const string UserContextCacheKey = "UmbracoUserContext"; public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout"; public const string UserCacheKey = "UmbracoUser"; + public const string UserPermissionsCacheKey = "UmbracoUserPermissions"; public const string ContentTypeCacheKey = "UmbracoContentType"; diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 41ceaf9b90..0e5c3340fa 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Models private DateTime? _expireDate; private int _writer; private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name. - + private bool _permissionsChanged; /// /// Constructor for creating a Content object /// @@ -82,6 +82,7 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ExpireDate); private static readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo(x => x.WriterId); private static readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeName); + private static readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo(x => x.PermissionsChanged); /// /// Gets or sets the template used by the Content. @@ -243,6 +244,22 @@ namespace Umbraco.Core.Models } } + /// + /// Used internally to track if permissions have been changed during the saving process for this entity + /// + internal bool PermissionsChanged + { + get { return _permissionsChanged; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _permissionsChanged = value; + return _permissionsChanged; + }, _permissionsChanged, PermissionsChangedSelector); + } + } + /// /// Gets the ContentType used by this content object /// diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 93179f7e91..755fc5f04a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -225,9 +225,14 @@ namespace Umbraco.Core.Persistence.Repositories // user's default permissions. if (parentPermissions.Any()) { - var userPermissions = parentPermissions.ToDictionary( - permissionDto => (object) permissionDto.UserId, permissionDto => permissionDto.Permission); + var userPermissions = parentPermissions.Select( + permissionDto => new KeyValuePair( + permissionDto.UserId, + permissionDto.Permission)); AssignEntityPermissions(entity, userPermissions); + //flag the entity's permissions changed flag so we can track those changes. + //Currently only used for the cache refreshers to detect if we should refresh all user permissions cache. + ((Content) entity).PermissionsChanged = true; } //Create the Content specific data - cmsContent @@ -296,6 +301,10 @@ namespace Umbraco.Core.Persistence.Repositories "SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType", new {ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId}); entity.SortOrder = maxSortOrder + 1; + + //Question: If we move a node, should we update permissions to inherit from the new parent if the parent has permissions assigned? + // if we do that, then we'd need to propogate permissions all the way downward which might not be ideal for many people. + // Gonna just leave it as is for now, and not re-propogate permissions. } var factory = new ContentFactory(NodeObjectTypeId, entity.Id); diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index 435fb9c7ef..adec7b6f85 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -10,6 +10,7 @@ using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.member; using System.Linq; using umbraco.cms.businesslogic.web; +using Content = Umbraco.Core.Models.Content; using Macro = umbraco.cms.businesslogic.macro.Macro; using Template = umbraco.cms.businesslogic.template.Template; @@ -123,8 +124,46 @@ namespace Umbraco.Web.Cache MediaService.Deleting += MediaServiceDeleting; MediaService.Moving += MediaServiceMoving; MediaService.Trashing += MediaServiceTrashing; + + ContentService.Created += ContentServiceCreated; + ContentService.Copied += ContentServiceCopied; } + #region Content service event handlers + + /// + /// When an entity is copied new permissions may be assigned to it based on it's parent, if that is the + /// case then we need to clear all user permissions cache. + /// + /// + /// + static void ContentServiceCopied(IContentService sender, Core.Events.CopyEventArgs e) + { + //check if permissions have changed + var permissionsChanged = ((Content)e.Copy).WasPropertyDirty("PermissionsChanged"); + if (permissionsChanged) + { + DistributedCache.Instance.RefreshAllUserPermissionsCache(); + } + } + + /// + /// When an entity is created new permissions may be assigned to it based on it's parent, if that is the + /// case then we need to clear all user permissions cache. + /// + /// + /// + static void ContentServiceCreated(IContentService sender, Core.Events.NewEventArgs e) + { + //check if permissions have changed + var permissionsChanged = ((Content)e.Entity).WasPropertyDirty("PermissionsChanged"); + if (permissionsChanged) + { + DistributedCache.Instance.RefreshAllUserPermissionsCache(); + } + } + #endregion + #region ApplicationTree event handlers static void ApplicationTreeNew(ApplicationTree sender, System.EventArgs e) { @@ -396,15 +435,15 @@ namespace Umbraco.Web.Cache { if (sender.User != null) { - DistributedCache.Instance.RefreshUserCache(sender.User.Id); + DistributedCache.Instance.RefreshUserPermissionsCache(sender.User.Id); } - if (sender.UserId > -1) + else if (sender.UserId > -1) { - DistributedCache.Instance.RefreshUserCache(sender.UserId); + DistributedCache.Instance.RefreshUserPermissionsCache(sender.UserId); } - if (sender.NodeIds.Any()) + else if (sender.NodeIds.Any()) { - DistributedCache.Instance.RefreshAllUserCache(); + DistributedCache.Instance.RefreshAllUserPermissionsCache(); } } diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index a0ce50d4c7..1f7307b289 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -43,6 +43,7 @@ namespace Umbraco.Web.Cache public const string MediaCacheRefresherId = "B29286DD-2D40-4DDB-B325-681226589FEC"; public const string MacroCacheRefresherId = "7B1E683C-5F34-43dd-803D-9699EA1E98CA"; public const string UserCacheRefresherId = "E057AF6D-2EE6-41F4-8045-3694010F0AA6"; + public const string UserPermissionsCacheRefresherId = "840AB9C5-5C0B-48DB-A77E-29FE4B80CD3A"; public const string UserTypeCacheRefresherId = "7E707E21-0195-4522-9A3C-658CC1761BD4"; public const string ContentTypeCacheRefresherId = "6902E22C-9C10-483C-91F3-66B7CAE9E2F5"; public const string LanguageCacheRefresherId = "3E0F95D8-0BE5-44B8-8394-2B8750B62654"; diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 5e46927d57..274705439e 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -61,6 +61,23 @@ namespace Umbraco.Web.Cache } #endregion + #region User permissions cache + public static void RemoveUserPermissionsCache(this DistributedCache dc, int userId) + { + dc.Remove(new Guid(DistributedCache.UserPermissionsCacheRefresherId), userId); + } + + public static void RefreshUserPermissionsCache(this DistributedCache dc, int userId) + { + dc.Refresh(new Guid(DistributedCache.UserPermissionsCacheRefresherId), userId); + } + + public static void RefreshAllUserPermissionsCache(this DistributedCache dc) + { + dc.RefreshAll(new Guid(DistributedCache.UserPermissionsCacheRefresherId)); + } + #endregion + #region Template cache /// /// Refreshes the cache amongst servers for a template diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index 0e4e32bc48..c80e8ed9b7 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -28,6 +28,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserCacheKey); + ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserContextCacheKey); } @@ -39,6 +40,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserCacheKey, id)); + ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); //we need to clear all UserContextCacheKey since we cannot invalidate based on ID since the cache is done so based //on the current contextId stored in the database diff --git a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs new file mode 100644 index 0000000000..fdafdedb09 --- /dev/null +++ b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs @@ -0,0 +1,47 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Cache; + +namespace Umbraco.Web.Cache +{ + /// + /// Used only to invalidate the user permissions cache + /// + /// + /// The UserCacheRefresher will also clear a user's permissions cache, this refresher is for invalidating only permissions + /// for users/content, not the users themselves. + /// + public sealed class UserPermissionsCacheRefresher : CacheRefresherBase + { + protected override UserPermissionsCacheRefresher Instance + { + get { return this; } + } + + public override Guid UniqueIdentifier + { + get { return Guid.Parse(DistributedCache.UserPermissionsCacheRefresherId); } + } + + + public override string Name + { + get { return "User permissions cache refresher"; } + } + + public override void RefreshAll() + { + ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); + } + + public override void Refresh(int id) + { + Remove(id); + } + + public override void Remove(int id) + { + ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs index f76198d2c3..1371c6fdb9 100644 --- a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs +++ b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs @@ -8,6 +8,8 @@ using Umbraco.Web.Cache; namespace Umbraco.Web.Strategies.Publishing { + //TODO: I think we should move this logic into the CacheRefresherEventHandler since all other handlers are registered there for invalidating cache. + /// /// Represents the UpdateCacheAfterPublish class, which subscribes to the Published event /// of the class and is responsible for doing the actual diff --git a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs index 7af7724c7e..39ca0beda3 100644 --- a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs +++ b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs @@ -10,6 +10,8 @@ using Umbraco.Web.Cache; namespace Umbraco.Web.Strategies.Publishing { + //TODO: I think we should move this logic into the CacheRefresherEventHandler since all other handlers are registered there for invalidating cache. + /// /// Represents the UpdateCacheAfterUnPublish class, which subscribes to the UnPublished event /// of the class and is responsible for doing the actual diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index d99c76a624..7d0761cf1e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -286,6 +286,7 @@ + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs index cf570d93c1..7a96b7ae3e 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs @@ -35,13 +35,8 @@ namespace umbraco.dialogs // Put user code to initialize the page here } - #region Web Form Designer generated code override protected void OnInit(EventArgs e) { - // - // CODEGEN: This call is required by the ASP.NET Web Form Designer. - // - InitializeComponent(); base.OnInit(e); node = new cms.businesslogic.CMSNode(int.Parse(helper.Request("id"))); @@ -99,15 +94,6 @@ namespace umbraco.dialogs PlaceHolder1.Controls.Add(ht); } - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - - } - #endregion protected void Button1_Click(object sender, System.EventArgs e) { diff --git a/src/umbraco.businesslogic/User.cs b/src/umbraco.businesslogic/User.cs index 3ee8608da0..5da83d2a6d 100644 --- a/src/umbraco.businesslogic/User.cs +++ b/src/umbraco.businesslogic/User.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Web.Caching; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; @@ -28,9 +29,6 @@ namespace umbraco.BusinessLogic private bool _userDisabled; private bool _defaultToLiveEditing; - private Hashtable _cruds = new Hashtable(); - private bool _crudsInitialized = false; - private Hashtable _notifications = new Hashtable(); private bool _notificationsInitialized = false; @@ -670,19 +668,42 @@ namespace umbraco.BusinessLogic setupUser(_id); string defaultPermissions = UserType.DefaultPermissions; - if (!_crudsInitialized) - initCruds(); + //get the cached permissions for the user + var cachedPermissions = ApplicationContext.Current.ApplicationCache.GetCacheItem( + string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, _id), + //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will make this priority below average + CacheItemPriority.BelowNormal, + null, + //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will only have this exist in cache for 20 minutes, + // then it will refresh from the database. + new TimeSpan(0, 20, 0), + () => + { + var cruds = new Hashtable(); + using (var dr = SqlHelper.ExecuteReader("select * from umbracoUser2NodePermission where userId = @userId order by nodeId", SqlHelper.CreateParameter("@userId", this.Id))) + { + while (dr.Read()) + { + if (!cruds.ContainsKey(dr.GetInt("nodeId"))) + { + cruds.Add(dr.GetInt("nodeId"), string.Empty); + } + cruds[dr.GetInt("nodeId")] += dr.GetString("permission"); + } + } + return cruds; + }); // NH 4.7.1 changing default permission behavior to default to User Type permissions IF no specific permissions has been // set for the current node - int nodeId = Path.Contains(",") ? int.Parse(Path.Substring(Path.LastIndexOf(",")+1)) : int.Parse(Path); - if (_cruds.ContainsKey(nodeId)) + var nodeId = Path.Contains(",") ? int.Parse(Path.Substring(Path.LastIndexOf(",", StringComparison.Ordinal)+1)) : int.Parse(Path); + if (cachedPermissions.ContainsKey(nodeId)) { - return _cruds[int.Parse(Path.Substring(Path.LastIndexOf(",")+1))].ToString(); + return cachedPermissions[int.Parse(Path.Substring(Path.LastIndexOf(",", StringComparison.Ordinal) + 1))].ToString(); } // exception to everything. If default cruds is empty and we're on root node; allow browse of root node - if (String.IsNullOrEmpty(defaultPermissions) && Path == "-1") + if (string.IsNullOrEmpty(defaultPermissions) && Path == "-1") defaultPermissions = "F"; // else return default user type cruds @@ -691,29 +712,10 @@ namespace umbraco.BusinessLogic /// /// Initializes the user node permissions - /// + /// + [Obsolete("This method doesn't do anything whatsoever and will be removed in future versions")] public void initCruds() - { - if (!_isInitialized) - setupUser(_id); - - // clear cruds - System.Web.HttpContext.Current.Application.Lock(); - _cruds.Clear(); - System.Web.HttpContext.Current.Application.UnLock(); - - using (IRecordsReader dr = SqlHelper.ExecuteReader("select * from umbracoUser2NodePermission where userId = @userId order by nodeId", SqlHelper.CreateParameter("@userId", this.Id))) - { - // int currentId = -1; - while (dr.Read()) - { - if (!_cruds.ContainsKey(dr.GetInt("nodeId"))) - _cruds.Add(dr.GetInt("nodeId"), String.Empty); - - _cruds[dr.GetInt("nodeId")] += dr.GetString("permission"); - } - } - _crudsInitialized = true; + { } /// From ba68da5736f194cb36a5222f09e21d0bf8779cd3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 9 Jul 2013 11:55:29 +1000 Subject: [PATCH 24/25] Makes Domain.GetDomains public (#U4-2483) --- src/umbraco.cms/businesslogic/web/Domain.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/umbraco.cms/businesslogic/web/Domain.cs b/src/umbraco.cms/businesslogic/web/Domain.cs index 83bbb850ac..f5bcb46090 100644 --- a/src/umbraco.cms/businesslogic/web/Domain.cs +++ b/src/umbraco.cms/businesslogic/web/Domain.cs @@ -138,12 +138,12 @@ namespace umbraco.cms.businesslogic.web #region Statics - internal static List GetDomains() + public static IEnumerable GetDomains() { return GetDomains(false); } - internal static List GetDomains(bool includeWildcards) + internal static IEnumerable GetDomains(bool includeWildcards) { var domains = ApplicationContext.Current.ApplicationCache.GetCacheItem( CacheKeys.DomainCacheKey, @@ -177,7 +177,7 @@ namespace umbraco.cms.businesslogic.web public static Domain GetDomain(string DomainName) { - return GetDomains().Find(delegate(Domain d) { return d.Name == DomainName; }); + return GetDomains().FirstOrDefault(d => d.Name == DomainName); } public static int GetRootFromDomain(string DomainName) @@ -189,7 +189,7 @@ namespace umbraco.cms.businesslogic.web public static Domain[] GetDomainsById(int nodeId) { - return GetDomains().FindAll(delegate(Domain d) { return d._root == nodeId; }).ToArray(); + return GetDomains().Where(d => d._root == nodeId).ToArray(); } public static bool Exists(string DomainName) From aa327696feb0dbe1d132491a49bf4f7f75d2ccef Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 10 Jul 2013 12:35:21 +0200 Subject: [PATCH 25/25] Fixes U4-2354 MiniProfiler - Show SQL parameter values and more stacktrace info Refactored duplicate code --- src/Umbraco.Core/Profiling/WebProfiler.cs | 46 +++++++++++------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Core/Profiling/WebProfiler.cs b/src/Umbraco.Core/Profiling/WebProfiler.cs index 56918ff349..3a1974279e 100644 --- a/src/Umbraco.Core/Profiling/WebProfiler.cs +++ b/src/Umbraco.Core/Profiling/WebProfiler.cs @@ -1,6 +1,7 @@ using System; using System.Web; using StackExchange.Profiling; +using StackExchange.Profiling.SqlFormatters; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; @@ -52,13 +53,8 @@ namespace Umbraco.Core.Profiling /// void UmbracoApplicationEndRequest(object sender, EventArgs e) { - if (GlobalSettings.DebugMode == false) return; - var request = TryGetRequest(sender); - if (request.Success == false) return; - if (request.Result.Url.IsClientSideRequest()) return; - if (string.IsNullOrEmpty(request.Result["umbDebug"]) == false) + if (CanPerformProfilingAction(sender)) { - //stop the profiler Stop(); } } @@ -70,17 +66,28 @@ namespace Umbraco.Core.Profiling /// void UmbracoApplicationBeginRequest(object sender, EventArgs e) { - if (GlobalSettings.DebugMode == false) return; - var request = TryGetRequest(sender); - if (request.Success == false) return; - if (request.Result.Url.IsClientSideRequest()) return; - if (string.IsNullOrEmpty(request.Result["umbDebug"]) == false) + if (CanPerformProfilingAction(sender)) { - //start the profiler Start(); } } + private bool CanPerformProfilingAction(object sender) + { + if (GlobalSettings.DebugMode == false) + return false; + + //will not run in medium trust + if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) + return false; + + var request = TryGetRequest(sender); + if (request.Success == false || request.Result.Url.IsClientSideRequest() || string.IsNullOrEmpty(request.Result["umbDebug"])) + return false; + + return true; + } + /// /// Render the UI to display the profiler /// @@ -103,9 +110,7 @@ namespace Umbraco.Core.Profiling /// public IDisposable Step(string name) { - if (GlobalSettings.DebugMode == false) return null; - - return MiniProfiler.Current.Step(name); + return GlobalSettings.DebugMode == false ? null : MiniProfiler.Current.Step(name); } /// @@ -113,10 +118,8 @@ namespace Umbraco.Core.Profiling /// public void Start() { - if (GlobalSettings.DebugMode == false) return; - //will not run in medium trust - if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) return; - + MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter(); + MiniProfiler.Settings.StackMaxLength = 5000; MiniProfiler.Start(); } @@ -129,10 +132,6 @@ namespace Umbraco.Core.Profiling /// public void Stop(bool discardResults = false) { - if (GlobalSettings.DebugMode == false) return; - //will not run in medium trust - if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) return; - MiniProfiler.Stop(discardResults); } @@ -156,6 +155,5 @@ namespace Umbraco.Core.Profiling return new Attempt(ex); } } - } } \ No newline at end of file