Merge release-7.4.2 into dev-v7-deploy
This commit is contained in:
@@ -15,11 +15,11 @@ If you're interested in making changes to Belle make sure to read the [Belle Rea
|
||||
|
||||
**More than 177,000 sites trust Umbraco**
|
||||
|
||||
For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developers dream and your users will love it too.
|
||||
For the first time on the Microsoft platform, there is a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developer's dream and your users will love it too.
|
||||
|
||||
Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales.
|
||||
Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)), you can be sure that the technology is proven, stable and scales.
|
||||
|
||||
To view more examples please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies)
|
||||
To view more examples, please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies)
|
||||
|
||||
## Downloading ##
|
||||
|
||||
@@ -35,6 +35,6 @@ If you want to contribute back to Umbraco you should check out our [guide to con
|
||||
|
||||
## Found a bug? ##
|
||||
|
||||
Another way you can contribute to Umbraco is by providing issue reports, for information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature).
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature).
|
||||
|
||||
To view existing issues please visit [http://issues.umbraco.org](http://issues.umbraco.org)
|
||||
To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
|
||||
@@ -21,14 +21,6 @@ ECHO Building Umbraco %version%
|
||||
|
||||
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
|
||||
|
||||
ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
|
||||
SET nuGetFolder=%CD%\..\src\packages\
|
||||
..\src\.nuget\NuGet.exe sources Remove -Name MyGetUmbracoCore >NUL
|
||||
..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
|
||||
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
|
||||
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
|
||||
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
|
||||
|
||||
+2
-2
@@ -175,8 +175,8 @@
|
||||
<!-- Copy SQL CE -->
|
||||
<ItemGroup>
|
||||
<SQLCE4Files
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.1\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.1\lib\**\*;..\src\packages\SqlServerCE.4.0.0.1\**\*.nu*"
|
||||
/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.2.29, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.0.1, 4.0.0)" />
|
||||
@@ -31,14 +30,13 @@
|
||||
<dependency id="ClientDependency" version="[1.8.4, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 9.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.3.2, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.5.1, 5.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.3.3, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.5.3, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebHelpers" version="[3.2.3, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebPages.Data" version="[3.2.3, 4.0.0)" />
|
||||
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
|
||||
<dependency id="Markdown" version="[1.14.4, 2.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.AspNet" version="[3.0.0-beta006, 3.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 9.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.2, 4.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -77,4 +77,8 @@
|
||||
<section alias="uGoLiveDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="Remove" />
|
||||
|
||||
<section alias="ExamineManagement" xdt:Locator="Match(alias)" xdt:Transform="Remove" />
|
||||
|
||||
<section alias="StartupDashboardSection">
|
||||
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
</section>
|
||||
</dashBoard>
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
|
||||
file (and config files in the config folder).
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
We've done our best to transform your configuration files but in case something is not quite right: remember we
|
||||
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<section name="ExamineLuceneIndexSets" type="Examine.LuceneEngine.Config.IndexSets, Examine" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type,requirePermission)" />
|
||||
|
||||
<sectionGroup name="applicationSettings" xdt:Locator="Match(name)">
|
||||
<section name="umbraco.presentation.Properties.Settings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</sectionGroup>
|
||||
<section name="umbraco.presentation.Properties.Settings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</sectionGroup>
|
||||
<sectionGroup name="system.web.webPages.razor" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<sectionGroup name="umbracoConfiguration" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing">
|
||||
<section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
@@ -21,8 +21,10 @@
|
||||
<appSettings xdt:Transform="InsertIfMissing" />
|
||||
<appSettings>
|
||||
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
<add key="Umbraco.ModelsBuilder.Enable" value="false" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
<add key="Umbraco.ModelsBuilder.ModelsMode" value="Nothing" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
</appSettings>
|
||||
|
||||
|
||||
<umbracoConfiguration xdt:Transform="InsertIfMissing">
|
||||
<settings configSource="config\umbracoSettings.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
<BaseRestExtensions configSource="config\BaseRestExtensions.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
@@ -37,7 +39,7 @@
|
||||
<DbProviderFactories xdt:Transform="InsertIfMissing">
|
||||
<remove invariant="System.Data.SqlServerCe.4.0" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
|
||||
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="Remove" />
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(type)" />
|
||||
@@ -48,13 +50,15 @@
|
||||
<system.web xdt:Transform="InsertIfMissing" />
|
||||
<system.web>
|
||||
<siteMap xdt:Transform="Remove" />
|
||||
<siteMap xdt:Transform="InsertIfMissing">
|
||||
<siteMap xdt:Transform="InsertIfMissing">
|
||||
<providers xdt:Transform="InsertIfMissing">
|
||||
<remove name="MySqlSiteMapProvider" xdt:Transform="InsertIfMissing" />
|
||||
</providers>
|
||||
</siteMap>
|
||||
</siteMap>
|
||||
<httpRuntime xdt:Transform="InsertIfMissing" />
|
||||
<httpRuntime targetFramework="4.5" maxRequestLength="51200" fcnMode="Single" xdt:Transform="SetAttributes(targetFramework,fcnMode,maxRequestLength)" />
|
||||
<httpRuntime maxRequestLength="51200" fcnMode="Single" xdt:Transform="SetAttributes(fcnMode,maxRequestLength)" />
|
||||
<httpRuntime targetFramework="4.5" xdt:Locator="Condition(count(@targetFramework) != 1)" xdt:Transform="SetAttributes(targetFramework)" />
|
||||
|
||||
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
|
||||
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
|
||||
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
|
||||
@@ -63,8 +67,7 @@
|
||||
<compilation>
|
||||
<assemblies xdt:Transform="InsertIfMissing" />
|
||||
<assemblies>
|
||||
<add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)"
|
||||
xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
@@ -78,6 +81,56 @@
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<add assembly="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<add assembly="System.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Collections.Concurrent, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ComponentModel.Annotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ComponentModel.EventBasedAsync, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Contracts, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Debug, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Tools, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Tracing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Dynamic.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Globalization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.IO, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq.Expressions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq.Queryable, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.NetworkInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.Requests, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ObjectModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Emit, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Emit.ILGeneration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Emit.Lightweight, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Resources.ResourceManager, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.InteropServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.InteropServices.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Serialization.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Serialization.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Serialization.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Security.Principal, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Duplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.NetTcp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Text.Encoding, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Text.Encoding.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Text.RegularExpressions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Threading, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Threading.Tasks, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Threading.Tasks.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Xml.ReaderWriter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Xml.XDocument, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Xml.XmlSerializer, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
|
||||
@@ -86,11 +139,113 @@
|
||||
<remove assembly="System.Web.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Collections" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Collections.Concurrent" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ComponentModel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ComponentModel.Annotations" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ComponentModel.EventBasedAsync" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Contracts" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Debug" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Tools" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Tracing" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Dynamic.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Globalization" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.IO" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq.Expressions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq.Queryable" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.NetworkInformation" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.Requests" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ObjectModel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Emit" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Emit.ILGeneration" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Emit.Lightweight" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Resources.ResourceManager" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.InteropServices" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.InteropServices.WindowsRuntime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Numerics" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Serialization.Json" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Serialization.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Serialization.Xml" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Security.Principal" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Duplex" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.NetTcp" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Security" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Text.Encoding" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Text.Encoding.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Text.RegularExpressions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Threading" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Threading.Tasks" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Threading.Tasks.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Xml.ReaderWriter" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Xml.XDocument" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Xml.XmlSerializer" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
<compilation>
|
||||
<assemblies>
|
||||
<remove assembly="System.Web.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Collections" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Collections.Concurrent" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ComponentModel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ComponentModel.Annotations" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ComponentModel.EventBasedAsync" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Contracts" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Debug" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Tools" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Tracing" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Dynamic.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Globalization" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.IO" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq.Expressions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq.Queryable" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.NetworkInformation" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.Requests" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ObjectModel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Emit" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Emit.ILGeneration" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Emit.Lightweight" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Resources.ResourceManager" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.InteropServices" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.InteropServices.WindowsRuntime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Numerics" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Serialization.Json" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Serialization.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Serialization.Xml" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Security.Principal" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Duplex" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.NetTcp" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Security" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Text.Encoding" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Text.Encoding.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Text.RegularExpressions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Threading" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Threading.Tasks" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Threading.Tasks.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Xml.ReaderWriter" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Xml.XDocument" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Xml.XmlSerializer" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
|
||||
@@ -125,6 +280,8 @@
|
||||
<add name="umbracoRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<!-- Note, we're removing the one that starts with a space here, don't correct it -->
|
||||
<!-- This to fix a quirk we for a lot of releases where we added it with the space by default -->
|
||||
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
</modules>
|
||||
@@ -149,16 +306,14 @@
|
||||
<requestLimits maxAllowedContentLength="52428800" xdt:Transform="InsertIfMissing" />
|
||||
</requestFiltering>
|
||||
</security>
|
||||
|
||||
</system.webServer>
|
||||
|
||||
<system.codedom xdt:Transform="Remove" />
|
||||
</system.webServer>
|
||||
|
||||
<runtime xdt:Transform="InsertIfMissing" />
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" xdt:Transform="InsertIfMissing" />
|
||||
</runtime>
|
||||
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='HtmlAgilityPack')" xdt:Transform="Remove" />
|
||||
@@ -171,7 +326,7 @@
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.OAuth')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.Cookies')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
@@ -180,7 +335,7 @@
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.9.0" newVersion="1.4.9.0" />
|
||||
</dependentAssembly>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
|
||||
@@ -191,12 +346,12 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
@@ -208,16 +363,16 @@
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
@@ -225,19 +380,19 @@
|
||||
</runtime>
|
||||
|
||||
<system.web.webPages.razor xdt:Transform="Remove" />
|
||||
|
||||
|
||||
<location path="umbraco" xdt:Locator="Match(path)" xdt:Transform="InsertIfMissing" />
|
||||
<location path="umbraco" xdt:Locator="Match(path)">
|
||||
<system.webServer xdt:Transform="InsertIfMissing">
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
</system.webServer>
|
||||
</location>
|
||||
|
||||
|
||||
<location path="App_Plugins" xdt:Locator="Match(path)" xdt:Transform="InsertIfMissing" />
|
||||
<location path="App_Plugins" xdt:Locator="Match(path)">
|
||||
<system.webServer xdt:Transform="InsertIfMissing">
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
</system.webServer>
|
||||
</location>
|
||||
|
||||
|
||||
</configuration>
|
||||
@@ -1,18 +1,30 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
|
||||
Write-Host "copyLogsPath:" "${copyLogsPath}"
|
||||
$umbracoBinFolder = Join-Path $projectPath "bin"
|
||||
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# After backing up, remove all umbraco dlls from bin folder in case dll files are included in the VS project
|
||||
# See: http://issues.umbraco.org/issue/U4-4930
|
||||
$umbracoBinFolder = Join-Path $projectDestinationPath "bin"
|
||||
|
||||
if(Test-Path $umbracoBinFolder) {
|
||||
$umbracoBinBackupPath = Join-Path $backupPath "bin"
|
||||
|
||||
@@ -20,7 +32,7 @@ if ($project) {
|
||||
|
||||
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
|
||||
|
||||
# Delete files Umbraco brings in
|
||||
# Delete files Umbraco ships with
|
||||
if(Test-Path $umbracoBinFolder\businesslogic.dll) { Remove-Item $umbracoBinFolder\businesslogic.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\cms.dll) { Remove-Item $umbracoBinFolder\cms.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\controls.dll) { Remove-Item $umbracoBinFolder\controls.dll -Force -Confirm:$false }
|
||||
@@ -36,16 +48,18 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\umbraco.DataLayer.dll) { Remove-Item $umbracoBinFolder\umbraco.DataLayer.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.editorControls.dll) { Remove-Item $umbracoBinFolder\umbraco.editorControls.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.MacroEngines.dll) { Remove-Item $umbracoBinFolder\umbraco.MacroEngines.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll) { Remove-Item $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll -Force -Confirm:$false }
|
||||
|
||||
# Delete files Umbraco depends upon
|
||||
$amd64Folder = Join-Path $projectDestinationPath "bin\amd64"
|
||||
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
|
||||
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $projectDestinationPath "bin\x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $umbracoBinFolder "x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\AutoMapper.dll) { Remove-Item $umbracoBinFolder\AutoMapper.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\AutoMapper.Net4.dll) { Remove-Item $umbracoBinFolder\AutoMapper.Net4.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\ClientDependency.Core.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.dll -Force -Confirm:$false }
|
||||
@@ -59,6 +73,8 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
|
||||
@@ -72,6 +88,8 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Collections.Immutable.dll) { Remove-Item $umbracoBinFolder\System.Collections.Immutable.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Reflection.Metadata.dll) { Remove-Item $umbracoBinFolder\System.Reflection.Metadata.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
|
||||
@@ -82,6 +100,6 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.Razor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Deployment.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Deployment.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,33 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
Write-Host "copyLogsPath:" "${copyLogsPath}"
|
||||
$webConfigSource = Join-Path $projectPath "Web.config"
|
||||
Write-Host "webConfigSource:" "${webConfigSource}"
|
||||
$configFolder = Join-Path $projectPath "Config"
|
||||
Write-Host "configFolder:" "${configFolder}"
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# Create a backup of original web.config
|
||||
$webConfigSource = Join-Path $projectDestinationPath "Web.config"
|
||||
Copy-Item $webConfigSource $backupPath -Force
|
||||
|
||||
# Backup config files folder
|
||||
$configFolder = Join-Path $projectDestinationPath "Config"
|
||||
# Backup config files folder
|
||||
if(Test-Path $configFolder) {
|
||||
$umbracoBackupPath = Join-Path $backupPath "Config"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
@@ -24,32 +36,24 @@ if ($project) {
|
||||
}
|
||||
|
||||
# Copy umbraco and umbraco_files from package to project folder
|
||||
# This is only done when these folders already exist because we
|
||||
# only want to do this for upgrades
|
||||
$umbracoFolder = Join-Path $projectDestinationPath "Umbraco"
|
||||
if(Test-Path $umbracoFolder) {
|
||||
$umbracoFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco"
|
||||
|
||||
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
}
|
||||
$umbracoFolder = Join-Path $projectPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoFolder
|
||||
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
|
||||
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
|
||||
$umbracoClientFolder = Join-Path $projectDestinationPath "Umbraco_Client"
|
||||
if(Test-Path $umbracoClientFolder) {
|
||||
$umbracoClientFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco_Client"
|
||||
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
}
|
||||
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientFolder
|
||||
$umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
|
||||
$copyWebconfig = $true
|
||||
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
|
||||
$destinationWebConfig = Join-Path $projectPath "Web.config"
|
||||
|
||||
if(Test-Path $destinationWebConfig)
|
||||
{
|
||||
@@ -71,11 +75,11 @@ if ($project) {
|
||||
|
||||
if($copyWebconfig -eq $true)
|
||||
{
|
||||
$packageWebConfigSource = Join-Path $rootPath "UmbracoFiles\Web.config"
|
||||
$packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config"
|
||||
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
|
||||
}
|
||||
|
||||
$installFolder = Join-Path $projectDestinationPath "Install"
|
||||
$installFolder = Join-Path $projectPath "Install"
|
||||
if(Test-Path $installFolder) {
|
||||
Remove-Item $installFolder -Force -Recurse -Confirm:$false
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.4.0
|
||||
beta4
|
||||
7.4.2
|
||||
@@ -47,13 +47,15 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
</packages>
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.4.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.4.0-beta4")]
|
||||
[assembly: AssemblyFileVersion("7.4.2")]
|
||||
[assembly: AssemblyInformationalVersion("7.4.2")]
|
||||
@@ -7,14 +7,22 @@ using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface describing this cache provider as a wrapper for another
|
||||
/// </summary>
|
||||
internal interface IRuntimeCacheProviderWrapper
|
||||
{
|
||||
IRuntimeCacheProvider InnerProvider { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns
|
||||
/// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are
|
||||
/// reset if the object is TracksChangesEntityBase
|
||||
/// </summary>
|
||||
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider
|
||||
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper
|
||||
{
|
||||
internal IRuntimeCacheProvider InnerProvider { get; private set; }
|
||||
public IRuntimeCacheProvider InnerProvider { get; private set; }
|
||||
|
||||
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
|
||||
{
|
||||
|
||||
@@ -11,35 +11,35 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
internal class DefaultRepositoryCachePolicy<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
|
||||
/// <remarks>
|
||||
/// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
|
||||
/// default policy with no expiry.
|
||||
/// </remarks>
|
||||
internal class DefaultRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private readonly RepositoryCachePolicyOptions _options;
|
||||
protected IRuntimeCacheProvider Cache { get; private set; }
|
||||
private Action _action;
|
||||
|
||||
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
: base(cache)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
|
||||
_options = options;
|
||||
Cache = cache;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public string GetCacheIdKey(object id)
|
||||
protected string GetCacheIdKey(object id)
|
||||
{
|
||||
if (id == null) throw new ArgumentNullException("id");
|
||||
|
||||
return string.Format("{0}{1}", GetCacheTypeKey(), id);
|
||||
}
|
||||
|
||||
public string GetCacheTypeKey()
|
||||
protected string GetCacheTypeKey()
|
||||
{
|
||||
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
|
||||
}
|
||||
|
||||
public void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
@@ -54,7 +54,9 @@ namespace Umbraco.Core.Cache
|
||||
//just to be safe, we cannot cache an item without an identity
|
||||
if (entity.HasIdentity)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity);
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity,
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
@@ -79,24 +81,29 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
persistMethod(entity);
|
||||
|
||||
//set the disposal action
|
||||
var cacheKey = GetCacheIdKey(entity.Id);
|
||||
SetCacheAction(() =>
|
||||
try
|
||||
{
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
persistMethod(entity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//set the disposal action
|
||||
var cacheKey = GetCacheIdKey(entity.Id);
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -113,13 +120,13 @@ namespace Umbraco.Core.Cache
|
||||
return entity;
|
||||
}
|
||||
|
||||
public TEntity Get(TId id)
|
||||
public override TEntity Get(TId id)
|
||||
{
|
||||
var cacheKey = GetCacheIdKey(id);
|
||||
return Cache.GetCacheItem<TEntity>(cacheKey);
|
||||
}
|
||||
|
||||
public bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -128,7 +135,7 @@ namespace Umbraco.Core.Cache
|
||||
return fromCache != null || getFromRepo(id);
|
||||
}
|
||||
|
||||
public virtual TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -182,7 +189,7 @@ namespace Umbraco.Core.Cache
|
||||
/// Looks up the zero count cache, must return null if it doesn't exist
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual bool HasZeroCountCache()
|
||||
protected bool HasZeroCountCache()
|
||||
{
|
||||
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
|
||||
return (zeroCount != null && zeroCount.Any() == false);
|
||||
@@ -192,24 +199,13 @@ namespace Umbraco.Core.Cache
|
||||
/// Performs the lookup for all entities of this type from the cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual TEntity[] GetAllFromCache()
|
||||
protected TEntity[] GetAllFromCache()
|
||||
{
|
||||
var allEntities = Cache.GetCacheItemsByKeySearch<TEntity>(GetCacheTypeKey())
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
return allEntities.Any() ? allEntities : new TEntity[] {};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The disposal performs the caching
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal for a single entity
|
||||
@@ -225,7 +221,9 @@ namespace Umbraco.Core.Cache
|
||||
//just to be safe, we cannot cache an item without an identity
|
||||
if (entity.HasIdentity)
|
||||
{
|
||||
Cache.InsertCacheItem(cacheKey, () => entity);
|
||||
Cache.InsertCacheItem(cacheKey, () => entity,
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -244,6 +242,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
//there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
|
||||
// to signify that there is a zero count cache
|
||||
//NOTE: Don't set expiry/sliding for a zero count
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {});
|
||||
}
|
||||
else
|
||||
@@ -256,20 +255,14 @@ namespace Umbraco.Core.Cache
|
||||
//just to be safe, we cannot cache an item without an identity
|
||||
if (localCopy.HasIdentity)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy);
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy,
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
protected void SetCacheAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,46 +11,190 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
|
||||
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache) : base(cache,
|
||||
new RepositoryCachePolicyOptions
|
||||
{
|
||||
//Definitely allow zero'd cache entires since this is a full set, in many cases there will be none,
|
||||
// and we must cache this!
|
||||
GetAllCacheAllowZeroCount = true
|
||||
})
|
||||
private readonly Func<TEntity, TId> _getEntityId;
|
||||
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
|
||||
private readonly bool _expires;
|
||||
|
||||
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
|
||||
: base(cache)
|
||||
{
|
||||
_getEntityId = getEntityId;
|
||||
_getAllFromRepo = getAllFromRepo;
|
||||
_expires = expires;
|
||||
}
|
||||
|
||||
private bool? _hasZeroCountCache;
|
||||
|
||||
|
||||
protected string GetCacheTypeKey()
|
||||
{
|
||||
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
|
||||
}
|
||||
|
||||
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
try
|
||||
{
|
||||
persistMethod(entity);
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
try
|
||||
{
|
||||
persistMethod(entity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return from the repo
|
||||
if (found == null) return getFromRepo(id);
|
||||
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
|
||||
if (entity == null) return null;
|
||||
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
return (TEntity)entity.DeepClone();
|
||||
}
|
||||
|
||||
public override TEntity Get(TId id)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return null
|
||||
if (found == null) return null;
|
||||
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
|
||||
if (entity == null) return null;
|
||||
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
return (TEntity)entity.DeepClone();
|
||||
}
|
||||
|
||||
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return from the repo
|
||||
return found == null
|
||||
? getFromRepo(id)
|
||||
: found.Any(x => _getEntityId(x).Equals(id));
|
||||
}
|
||||
|
||||
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
//process getting all including setting the cache callback
|
||||
var result = PerformGetAll(getFromRepo);
|
||||
|
||||
//now that the base result has been calculated, they will all be cached.
|
||||
// Now we can just filter by ids if they have been supplied
|
||||
|
||||
return (ids.Any()
|
||||
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
|
||||
: result)
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
.Select(x => (TEntity)x.DeepClone())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private TEntity[] PerformGetAll(Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
var allEntities = GetAllFromCache();
|
||||
if (allEntities.Any())
|
||||
{
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
//check the zero count cache
|
||||
if (HasZeroCountCache())
|
||||
{
|
||||
//there is a zero count cache so return an empty list
|
||||
return new TEntity[] { };
|
||||
}
|
||||
|
||||
//we need to do the lookup from the repo
|
||||
var entityCollection = getFromRepo(new TId[] { })
|
||||
//ensure we don't include any null refs in the returned collection!
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(entityCollection);
|
||||
|
||||
return entityCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For this type of caching policy, we don't cache individual items
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="entity"></param>
|
||||
protected override void SetCacheAction(string cacheKey, TEntity entity)
|
||||
protected void SetCacheAction(string cacheKey, TEntity entity)
|
||||
{
|
||||
//do nothing
|
||||
//No-op
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal for an entity collection
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="entityCollection"></param>
|
||||
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
|
||||
protected void SetCacheAction(TEntity[] entityCollection)
|
||||
{
|
||||
//for this type of caching policy, we don't want to cache any GetAll request containing specific Ids
|
||||
if (ids.Any()) return;
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//We want to cache the result as a single collection
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
|
||||
|
||||
if (_expires)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection),
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,7 +202,7 @@ namespace Umbraco.Core.Cache
|
||||
/// Looks up the zero count cache, must return null if it doesn't exist
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override bool HasZeroCountCache()
|
||||
protected bool HasZeroCountCache()
|
||||
{
|
||||
if (_hasZeroCountCache.HasValue)
|
||||
return _hasZeroCountCache.Value;
|
||||
@@ -71,14 +215,15 @@ namespace Umbraco.Core.Cache
|
||||
/// This policy will cache the full data set as a single collection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override TEntity[] GetAllFromCache()
|
||||
protected TEntity[] GetAllFromCache()
|
||||
{
|
||||
var found = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey());
|
||||
|
||||
|
||||
//This method will get called before checking for zero count cache, so we'll just set the flag here
|
||||
_hasZeroCountCache = found != null;
|
||||
|
||||
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
@@ -11,15 +13,21 @@ namespace Umbraco.Core.Cache
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
|
||||
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache)
|
||||
private readonly Func<TEntity, TId> _getEntityId;
|
||||
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
|
||||
private readonly bool _expires;
|
||||
|
||||
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
|
||||
{
|
||||
_runtimeCache = runtimeCache;
|
||||
_runtimeCache = runtimeCache;
|
||||
_getEntityId = getEntityId;
|
||||
_getAllFromRepo = getAllFromRepo;
|
||||
_expires = expires;
|
||||
}
|
||||
|
||||
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
|
||||
{
|
||||
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache);
|
||||
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,7 @@ namespace Umbraco.Core.Cache
|
||||
TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
|
||||
TEntity Get(TId id);
|
||||
bool Exists(TId id, Func<TId, bool> getFromRepo);
|
||||
|
||||
string GetCacheIdKey(object id);
|
||||
string GetCacheTypeKey();
|
||||
|
||||
void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
|
||||
void Remove(TEntity entity, Action<TEntity> persistMethod);
|
||||
TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
internal abstract class RepositoryCachePolicyBase<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private Action _action;
|
||||
|
||||
protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
protected IRuntimeCacheProvider Cache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The disposal performs the caching
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
protected void SetCacheAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public abstract TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
|
||||
public abstract TEntity Get(TId id);
|
||||
public abstract bool Exists(TId id, Func<TId, bool> getFromRepo);
|
||||
public abstract void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
|
||||
public abstract void Remove(TEntity entity, Action<TEntity> persistMethod);
|
||||
public abstract TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
|
||||
{
|
||||
//do nothing
|
||||
//no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
@@ -314,7 +314,7 @@ namespace Umbraco.Core
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
|
||||
@@ -374,7 +374,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
|
||||
@@ -400,7 +400,7 @@ namespace Umbraco.Core
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
@@ -409,6 +409,20 @@ namespace Umbraco.Core
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
|
||||
{
|
||||
HttpRuntimeCacheProvider cache;
|
||||
var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
|
||||
if (wrapper != null)
|
||||
{
|
||||
cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,18 +14,24 @@ namespace Umbraco.Core.Collections
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class DeepCloneableList<T> : List<T>, IDeepCloneable, IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that is empty and has the default initial capacity.
|
||||
/// </summary>
|
||||
public DeepCloneableList()
|
||||
private readonly ListCloneBehavior _listCloneBehavior;
|
||||
|
||||
public DeepCloneableList(ListCloneBehavior listCloneBehavior)
|
||||
{
|
||||
_listCloneBehavior = listCloneBehavior;
|
||||
}
|
||||
|
||||
public DeepCloneableList(IEnumerable<T> collection, ListCloneBehavior listCloneBehavior) : base(collection)
|
||||
{
|
||||
_listCloneBehavior = listCloneBehavior;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
|
||||
/// Default behavior is CloneOnce
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection whose elements are copied to the new list.</param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception>
|
||||
public DeepCloneableList(IEnumerable<T> collection) : base(collection)
|
||||
/// <param name="collection"></param>
|
||||
public DeepCloneableList(IEnumerable<T> collection)
|
||||
: this(collection, ListCloneBehavior.CloneOnce)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -35,20 +41,47 @@ namespace Umbraco.Core.Collections
|
||||
/// <returns></returns>
|
||||
public object DeepClone()
|
||||
{
|
||||
var newList = new DeepCloneableList<T>();
|
||||
foreach (var item in this)
|
||||
switch (_listCloneBehavior)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add((T) dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(item);
|
||||
}
|
||||
case ListCloneBehavior.CloneOnce:
|
||||
//we are cloning once, so create a new list in none mode
|
||||
// and deep clone all items into it
|
||||
var newList = new DeepCloneableList<T>(ListCloneBehavior.None);
|
||||
foreach (var item in this)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add((T)dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(item);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
case ListCloneBehavior.None:
|
||||
//we are in none mode, so just return a new list with the same items
|
||||
return new DeepCloneableList<T>(this, ListCloneBehavior.None);
|
||||
case ListCloneBehavior.Always:
|
||||
//always clone to new list
|
||||
var newList2 = new DeepCloneableList<T>(ListCloneBehavior.Always);
|
||||
foreach (var item in this)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList2.Add((T)dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList2.Add(item);
|
||||
}
|
||||
}
|
||||
return newList2;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public bool IsDirty()
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
internal enum ListCloneBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// When set, DeepClone will clone the items one time and the result list behavior will be None
|
||||
/// </summary>
|
||||
CloneOnce,
|
||||
|
||||
/// <summary>
|
||||
/// When set, DeepClone will not clone any items
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// When set, DeepClone will always clone all items
|
||||
/// </summary>
|
||||
Always
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.4.0");
|
||||
private static readonly Version Version = new Version("7.4.2");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "beta4"; } }
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -10,6 +10,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class Web
|
||||
{
|
||||
public const string UmbracoContextDataToken = "umbraco-context";
|
||||
public const string UmbracoDataToken = "umbraco";
|
||||
public const string PublishedDocumentRequestDataToken = "umbraco-doc-request";
|
||||
public const string CustomRouteDataToken = "umbraco-custom-route";
|
||||
public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def";
|
||||
|
||||
/// <summary>
|
||||
/// The preview cookie name
|
||||
/// </summary>
|
||||
|
||||
@@ -136,7 +136,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationInitialized", x.GetType())))
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -299,7 +302,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarting", x.GetType())))
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -350,7 +356,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarted", x.GetType())))
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
/// <summary>
|
||||
/// This will check enable dynamic access to properties and methods in a case insensitive manner
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// This works by using reflection on the type - the reflection lookup is lazy so it will not execute unless a dynamic method needs to be accessed
|
||||
/// </remarks>
|
||||
public abstract class CaseInsensitiveDynamicObject<T> : DynamicObject
|
||||
where T: class
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for dynamic access for case insensitive property access
|
||||
/// </summary>`
|
||||
private static readonly Lazy<IDictionary<string, Func<T, object>>> CaseInsensitivePropertyAccess = new Lazy<IDictionary<string, Func<T, object>>>(() =>
|
||||
{
|
||||
var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.DistinctBy(x => x.Name);
|
||||
return props.Select(propInfo =>
|
||||
{
|
||||
var name = propInfo.Name.ToLowerInvariant();
|
||||
Func<T, object> getVal = propInfo.GetValue;
|
||||
return new KeyValuePair<string, Func<T, object>>(name, getVal);
|
||||
|
||||
}).ToDictionary(x => x.Key, x => x.Value);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Used for dynamic access for case insensitive property access
|
||||
/// </summary>
|
||||
private static readonly Lazy<IDictionary<string, Tuple<ParameterInfo[], Func<T, object[], object>>>> CaseInsensitiveMethodAccess
|
||||
= new Lazy<IDictionary<string, Tuple<ParameterInfo[], Func<T, object[], object>>>>(() =>
|
||||
{
|
||||
var props = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(x => x.IsSpecialName == false && x.IsVirtual == false)
|
||||
.DistinctBy(x => x.Name);
|
||||
return props.Select(methodInfo =>
|
||||
{
|
||||
var name = methodInfo.Name.ToLowerInvariant();
|
||||
Func<T, object[], object> getVal = methodInfo.Invoke;
|
||||
var val = new Tuple<ParameterInfo[], Func<T, object[], object>>(methodInfo.GetParameters(), getVal);
|
||||
return new KeyValuePair<string, Tuple<ParameterInfo[], Func<T, object[], object>>>(name, val);
|
||||
|
||||
}).ToDictionary(x => x.Key, x => x.Value);
|
||||
});
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
var name = binder.Name.ToLowerInvariant();
|
||||
if (CaseInsensitiveMethodAccess.Value.ContainsKey(name) == false)
|
||||
return base.TryInvokeMember(binder, args, out result);
|
||||
|
||||
var val = CaseInsensitiveMethodAccess.Value[name];
|
||||
var parameters = val.Item1;
|
||||
var callback = val.Item2;
|
||||
var fullArgs = new List<object>(args);
|
||||
if (args.Length <= parameters.Length)
|
||||
{
|
||||
//need to fill them up if they're optional
|
||||
for (var i = args.Length; i < parameters.Length; i++)
|
||||
{
|
||||
if (parameters[i].IsOptional)
|
||||
{
|
||||
fullArgs.Add(parameters[i].DefaultValue);
|
||||
}
|
||||
}
|
||||
if (fullArgs.Count == parameters.Length)
|
||||
{
|
||||
result = callback((T)(object)this, fullArgs.ToArray());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return base.TryInvokeMember(binder, args, out result);
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
var name = binder.Name.ToLowerInvariant();
|
||||
if (CaseInsensitivePropertyAccess.Value.ContainsKey(name) == false)
|
||||
return base.TryGetMember(binder, out result);
|
||||
|
||||
result = CaseInsensitivePropertyAccess.Value[name]((T)(object)this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Dynamics
|
||||
/// </summary>
|
||||
public class DynamicXmlConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
var convertableTypes = new[]
|
||||
{
|
||||
@@ -78,8 +78,8 @@ namespace Umbraco.Core.Dynamics
|
||||
typeof(RawXmlDocument)
|
||||
};
|
||||
|
||||
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType))
|
||||
|| base.CanConvertFrom(context, sourceType);
|
||||
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType))
|
||||
|| base.CanConvertFrom(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(
|
||||
|
||||
@@ -5,8 +5,10 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Web.Services.Description;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
@@ -20,6 +22,20 @@ namespace Umbraco.Core.Dynamics
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]> MethodCache = new ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]>();
|
||||
|
||||
private static IEnumerable<Type> GetTypes(Assembly a)
|
||||
{
|
||||
try
|
||||
{
|
||||
return TypeFinder.GetTypesWithFormattedException(a);
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
// is this going to flood the log?
|
||||
LogHelper.Error(typeof (ExtensionMethodFinder), "Failed to get types.", ex);
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the enumerable of all extension method info's in the app domain = USE SPARINGLY!!!
|
||||
/// </summary>
|
||||
@@ -36,7 +52,7 @@ namespace Umbraco.Core.Dynamics
|
||||
// assemblies that contain extension methods
|
||||
.Where(a => a.IsDefined(typeof (ExtensionAttribute), false))
|
||||
// types that contain extension methods
|
||||
.SelectMany(a => a.GetTypes()
|
||||
.SelectMany(a => GetTypes(a)
|
||||
.Where(t => t.IsDefined(typeof (ExtensionAttribute), false) && t.IsSealed && t.IsGenericType == false && t.IsNested == false))
|
||||
// actual extension methods
|
||||
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public)
|
||||
@@ -45,9 +61,9 @@ namespace Umbraco.Core.Dynamics
|
||||
.Concat(typeof (Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public))
|
||||
//If we don't do this then we'll be scanning all assemblies each time!
|
||||
.ToArray(),
|
||||
|
||||
|
||||
//only cache for 5 minutes
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
|
||||
//each time this is accessed it will be for 5 minutes longer
|
||||
isSliding:true);
|
||||
@@ -57,7 +73,7 @@ namespace Umbraco.Core.Dynamics
|
||||
/// Returns all extension methods found matching the definition
|
||||
/// </summary>
|
||||
/// <param name="runtimeCache">
|
||||
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
|
||||
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
|
||||
/// while we search for individual extension methods, the process will be reasonably 'quick'. We then statically
|
||||
/// cache the MethodInfo's that we are looking for and then the runtime cache will expire and give back all that memory.
|
||||
/// </param>
|
||||
@@ -78,7 +94,7 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
var candidates = GetAllExtensionMethodsInAppDomain(runtimeCache);
|
||||
|
||||
// filter by name
|
||||
// filter by name
|
||||
var filtr1 = candidates.Where(m => m.Name == name);
|
||||
|
||||
// filter by args count
|
||||
@@ -102,7 +118,7 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
return filtr3.ToArray();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
|
||||
@@ -123,12 +139,12 @@ namespace Umbraco.Core.Dynamics
|
||||
types = method.GetParameters().Select(pi => pi.ParameterType).Skip(1)
|
||||
});
|
||||
|
||||
//This type comparer will check
|
||||
//This type comparer will check
|
||||
var typeComparer = new DelegateEqualityComparer<Type>(
|
||||
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
|
||||
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
|
||||
// example, if the argument type is HtmlHelper<MyModel> but the method parameter type is HtmlHelper then
|
||||
// it will match because the argument is assignable to that parameter type and will be able to execute
|
||||
TypeHelper.IsTypeAssignableFrom,
|
||||
TypeHelper.IsTypeAssignableFrom,
|
||||
//This will not ever execute but if it does we need to get the hash code of the string because the hash
|
||||
// code of a type is random
|
||||
type => type.FullName.GetHashCode());
|
||||
@@ -159,7 +175,7 @@ namespace Umbraco.Core.Dynamics
|
||||
.ToArray();
|
||||
|
||||
var methods = GetAllExtensionMethods(runtimeCache, thisType, name, args.Length).ToArray();
|
||||
|
||||
|
||||
return DetermineMethodFromParams(methods, genericType, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Semver;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
@@ -13,23 +14,49 @@ namespace Umbraco.Core.Events
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="productName"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, string productName, bool canCancel)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, productName, canCancel)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
[Obsolete("Use constructor accepting a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName, canCancel)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting SemVersion instances and a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ConfiguredSemVersion = new SemVersion(configuredVersion);
|
||||
TargetSemVersion = new SemVersion(targetVersion);
|
||||
}
|
||||
: this(eventObject, null, new SemVersion(configuredVersion), new SemVersion(targetVersion), GlobalSettings.UmbracoMigrationName, canCancel)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="migrationContext"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="productName"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, string productName, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
MigrationContext = migrationContext;
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
ProductName = productName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
@@ -39,12 +66,15 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
[Obsolete("Use constructor accepting a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
MigrationContext = migrationContext;
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
ProductName = GlobalSettings.UmbracoMigrationName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,21 +83,28 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
|
||||
: base(eventObject)
|
||||
{
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
/// <param name="productName"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, string productName)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, productName, false)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
[Obsolete("Use constructor accepting a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName, false)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting SemVersion instances and a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion)
|
||||
: base(eventObject)
|
||||
{
|
||||
ConfiguredSemVersion = new SemVersion(configuredVersion);
|
||||
TargetSemVersion = new SemVersion(targetVersion);
|
||||
}
|
||||
: this(eventObject, null, new SemVersion(configuredVersion), new SemVersion(targetVersion), GlobalSettings.UmbracoMigrationName, false)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Returns all migrations that were used in the migration runner
|
||||
@@ -95,6 +132,8 @@ namespace Umbraco.Core.Events
|
||||
|
||||
public SemVersion TargetSemVersion { get; private set; }
|
||||
|
||||
public string ProductName { get; private set; }
|
||||
|
||||
internal MigrationContext MigrationContext { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias of the default Template.
|
||||
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
|
||||
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
|
||||
/// we should not store direct entity
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public ITemplate DefaultTemplate
|
||||
@@ -79,6 +82,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets a list of Templates which are allowed for the ContentType
|
||||
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
|
||||
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
|
||||
/// we should not store direct entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<ITemplate> AllowedTemplates
|
||||
|
||||
@@ -487,11 +487,8 @@ namespace Umbraco.Core.Models
|
||||
var oldPropertyGroup = PropertyGroups.FirstOrDefault(x =>
|
||||
x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias));
|
||||
|
||||
// reset PropertyGroupId, which will be re-evaluated when the content type
|
||||
// is saved - what is important is group.PropertyTypes - see code in
|
||||
// ContentTypeBaseRepository.PersistUpdatedBaseContentType
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => default(int));
|
||||
propertyType.ResetDirtyProperties(); // PropertyGroupId must not be dirty
|
||||
// set new group
|
||||
propertyType.PropertyGroupId = newPropertyGroup == null ? null : new Lazy<int>(() => newPropertyGroup.Id, false);
|
||||
|
||||
// remove from old group, if any - add to new group, if any
|
||||
if (oldPropertyGroup != null)
|
||||
@@ -540,7 +537,7 @@ namespace Umbraco.Core.Models
|
||||
// re-assign the group's properties to no group
|
||||
foreach (var property in group.PropertyTypes)
|
||||
{
|
||||
property.PropertyGroupId = new Lazy<int>(() => 0);
|
||||
property.PropertyGroupId = null;
|
||||
_propertyTypes.Add(property);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,30 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the metadata for the properties for a given type so we know how to create them
|
||||
/// </summary>
|
||||
private struct ClonePropertyInfo
|
||||
{
|
||||
public ClonePropertyInfo(PropertyInfo propertyInfo) : this()
|
||||
{
|
||||
if (propertyInfo == null) throw new ArgumentNullException("propertyInfo");
|
||||
PropertyInfo = propertyInfo;
|
||||
}
|
||||
|
||||
public PropertyInfo PropertyInfo { get; private set; }
|
||||
public bool IsDeepCloneable { get; set; }
|
||||
public Type GenericListType { get; set; }
|
||||
public bool IsList
|
||||
{
|
||||
get { return GenericListType != null; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to avoid constant reflection (perf)
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Type, ClonePropertyInfo[]> PropCache = new ConcurrentDictionary<Type, ClonePropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
|
||||
@@ -30,81 +50,99 @@ namespace Umbraco.Core.Models
|
||||
throw new InvalidOperationException("Both the input and output types must be the same");
|
||||
}
|
||||
|
||||
//get the property metadata from cache so we only have to figure this out once per type
|
||||
var refProperties = PropCache.GetOrAdd(inputType, type =>
|
||||
inputType.GetProperties()
|
||||
.Where(x =>
|
||||
//is not attributed with the ignore clone attribute
|
||||
x.GetCustomAttribute<DoNotCloneAttribute>() == null
|
||||
.Select<PropertyInfo, ClonePropertyInfo?>(propertyInfo =>
|
||||
{
|
||||
if (
|
||||
//is not attributed with the ignore clone attribute
|
||||
propertyInfo.GetCustomAttribute<DoNotCloneAttribute>() != null
|
||||
//reference type but not string
|
||||
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|
||||
|| propertyInfo.PropertyType.IsValueType || propertyInfo.PropertyType == typeof (string)
|
||||
//settable
|
||||
&& x.CanWrite
|
||||
|| propertyInfo.CanWrite == false
|
||||
//non-indexed
|
||||
&& x.GetIndexParameters().Any() == false)
|
||||
|| propertyInfo.GetIndexParameters().Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
{
|
||||
return new ClonePropertyInfo(propertyInfo) { IsDeepCloneable = true };
|
||||
}
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
{
|
||||
if (propertyInfo.PropertyType.IsGenericType
|
||||
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
|
||||
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
|
||||
return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType };
|
||||
}
|
||||
if (propertyInfo.PropertyType.IsArray
|
||||
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
|
||||
{
|
||||
//if its an array, we'll create a list to work with first and then convert to array later
|
||||
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
|
||||
return new ClonePropertyInfo(propertyInfo) { GenericListType = typeof(List<object>) };
|
||||
}
|
||||
//skip instead of trying to create instance of abstract or interface
|
||||
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//its a custom IEnumerable, we'll try to create it
|
||||
try
|
||||
{
|
||||
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
//if it's an IList we can work with it, otherwise we cannot
|
||||
var newList = custom as IList;
|
||||
if (newList == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new ClonePropertyInfo(propertyInfo) {GenericListType = propertyInfo.PropertyType};
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//could not create this type so we'll skip it
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new ClonePropertyInfo(propertyInfo);
|
||||
})
|
||||
.Where(x => x.HasValue)
|
||||
.Select(x => x.Value)
|
||||
.ToArray());
|
||||
|
||||
foreach (var propertyInfo in refProperties)
|
||||
foreach (var clonePropertyInfo in refProperties)
|
||||
{
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
if (clonePropertyInfo.IsDeepCloneable)
|
||||
{
|
||||
//this ref property is also deep cloneable so clone it
|
||||
var result = (IDeepCloneable)propertyInfo.GetValue(input, null);
|
||||
var result = (IDeepCloneable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
//set the cloned value to the property
|
||||
propertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
}
|
||||
}
|
||||
else if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
else if (clonePropertyInfo.IsList)
|
||||
{
|
||||
IList newList;
|
||||
if (propertyInfo.PropertyType.IsGenericType
|
||||
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
|
||||
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
|
||||
newList = (IList)Activator.CreateInstance(genericType);
|
||||
}
|
||||
else if (propertyInfo.PropertyType.IsArray
|
||||
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
|
||||
{
|
||||
//if its an array, we'll create a list to work with first and then convert to array later
|
||||
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
|
||||
newList = new List<object>();
|
||||
}
|
||||
else
|
||||
{
|
||||
//skip instead of trying to create instance of abstract or interface
|
||||
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//its a custom IEnumerable, we'll try to create it
|
||||
try
|
||||
{
|
||||
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
//if it's an IList we can work with it, otherwise we cannot
|
||||
newList = custom as IList;
|
||||
if (newList == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//could not create this type so we'll skip it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var enumerable = (IEnumerable)propertyInfo.GetValue(input, null);
|
||||
var enumerable = (IEnumerable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
|
||||
if (enumerable == null) continue;
|
||||
|
||||
var newList = (IList)Activator.CreateInstance(clonePropertyInfo.GenericListType);
|
||||
|
||||
var isUsableType = true;
|
||||
|
||||
//now clone each item
|
||||
@@ -136,21 +174,21 @@ namespace Umbraco.Core.Models
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType.IsArray)
|
||||
if (clonePropertyInfo.PropertyInfo.PropertyType.IsArray)
|
||||
{
|
||||
//need to convert to array
|
||||
var arr = (object[])Activator.CreateInstance(propertyInfo.PropertyType, newList.Count);
|
||||
var arr = (object[])Activator.CreateInstance(clonePropertyInfo.PropertyInfo.PropertyType, newList.Count);
|
||||
for (int i = 0; i < newList.Count; i++)
|
||||
{
|
||||
arr[i] = newList[i];
|
||||
}
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, arr, null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, arr, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, newList, null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, newList, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary
|
||||
public interface IMediaType : IContentTypeComposition
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <param name="newAlias"></param>
|
||||
/// <returns></returns>
|
||||
IMediaType DeepCloneWithResetIdentities(string newAlias);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal static class MediaExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Hack: we need to put this in a real place, this is currently just used to render the urls for a media item in the back office
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetUrl(this IMedia media, string propertyAlias, ILogger logger)
|
||||
{
|
||||
var propertyType = media.PropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyAlias));
|
||||
if (propertyType != null)
|
||||
{
|
||||
var val = media.Properties[propertyType];
|
||||
if (val != null)
|
||||
{
|
||||
var jsonString = val.Value as string;
|
||||
if (jsonString != null)
|
||||
{
|
||||
if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.ImageCropperAlias)
|
||||
{
|
||||
if (jsonString.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<JObject>(jsonString);
|
||||
if (json["src"] != null)
|
||||
{
|
||||
return json["src"].Value<string>();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error<ImageCropperValueConverter>("Could not parse the string " + jsonString + " to a json object", ex);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return jsonString;
|
||||
}
|
||||
}
|
||||
else if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias)
|
||||
{
|
||||
return jsonString;
|
||||
}
|
||||
//hrm, without knowing what it is, just adding a string here might not be very nice
|
||||
}
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hack: we need to put this in a real place, this is currently just used to render the urls for a media item in the back office
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string[] GetUrls(this IMedia media, IContentSection contentSection, ILogger logger)
|
||||
{
|
||||
var links = new List<string>();
|
||||
var autoFillProperties = contentSection.ImageAutoFillProperties.ToArray();
|
||||
if (autoFillProperties.Any())
|
||||
{
|
||||
links.AddRange(
|
||||
autoFillProperties
|
||||
.Select(field => media.GetUrl(field.Alias, logger))
|
||||
.Where(link => link.IsNullOrWhiteSpace() == false));
|
||||
}
|
||||
return links.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,5 +38,30 @@ namespace Umbraco.Core.Models
|
||||
: base(parent, alias)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IMediaType DeepCloneWithResetIdentities(string alias)
|
||||
{
|
||||
var clone = (MediaType)DeepClone();
|
||||
clone.Alias = alias;
|
||||
clone.Key = Guid.Empty;
|
||||
foreach (var propertyGroup in clone.PropertyGroups)
|
||||
{
|
||||
propertyGroup.ResetIdentity();
|
||||
propertyGroup.ResetDirtyProperties(false);
|
||||
}
|
||||
foreach (var propertyType in clone.PropertyTypes)
|
||||
{
|
||||
propertyType.ResetIdentity();
|
||||
propertyType.ResetDirtyProperties(false);
|
||||
}
|
||||
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,8 +221,9 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the PropertyGroup's Id for which this PropertyType belongs
|
||||
/// Gets or sets the identifier of the PropertyGroup this PropertyType belongs to.
|
||||
/// </summary>
|
||||
/// <remarks>For generic properties, the value is <c>null</c>.</remarks>
|
||||
[DataMember]
|
||||
internal Lazy<int> PropertyGroupId
|
||||
{
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Caching;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
@@ -16,6 +13,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public class PublishedContentType
|
||||
{
|
||||
private readonly PublishedPropertyType[] _propertyTypes;
|
||||
private readonly HashSet<string> _compositionAliases;
|
||||
|
||||
// fast alias-to-index xref containing both the raw alias and its lowercase version
|
||||
private readonly Dictionary<string, int> _indexes = new Dictionary<string, int>();
|
||||
@@ -27,6 +25,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
Id = contentType.Id;
|
||||
Alias = contentType.Alias;
|
||||
_compositionAliases = new HashSet<string>(contentType.CompositionAliases(), StringComparer.InvariantCultureIgnoreCase);
|
||||
_propertyTypes = contentType.CompositionPropertyTypes
|
||||
.Select(x => new PublishedPropertyType(this, x))
|
||||
.ToArray();
|
||||
@@ -34,10 +33,11 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
// internal so it can be used for unit tests
|
||||
internal PublishedContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
internal PublishedContentType(int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
{
|
||||
Id = id;
|
||||
Alias = alias;
|
||||
_compositionAliases = new HashSet<string>(compositionAliases, StringComparer.InvariantCultureIgnoreCase);
|
||||
_propertyTypes = propertyTypes.ToArray();
|
||||
foreach (var propertyType in _propertyTypes)
|
||||
propertyType.ContentType = this;
|
||||
@@ -45,8 +45,8 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
// create detached content type - ie does not match anything in the DB
|
||||
internal PublishedContentType(string alias, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
: this (0, alias, propertyTypes)
|
||||
internal PublishedContentType(string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
: this(0, alias, compositionAliases, propertyTypes)
|
||||
{ }
|
||||
|
||||
private void InitializeIndexes()
|
||||
@@ -63,6 +63,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string Alias { get; private set; }
|
||||
public HashSet<string> CompositionAliases { get { return _compositionAliases; } }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -113,10 +114,25 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
internal static void ClearContentType(int id)
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear content type w/id {0}.", () => id);
|
||||
// requires a predicate because the key does not contain the ID
|
||||
// faster than key strings comparisons anyway
|
||||
|
||||
// we don't support "get all" at the moment - so, cheating
|
||||
var all = ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItemsByKeySearch<PublishedContentType>("PublishedContentType_").ToArray();
|
||||
|
||||
// the one we want to clear
|
||||
var clr = all.FirstOrDefault(x => x.Id == id);
|
||||
if (clr == null) return;
|
||||
|
||||
// those that have that one in their composition aliases
|
||||
// note: CompositionAliases contains all recursive aliases
|
||||
var oth = all.Where(x => x.CompositionAliases.InvariantContains(clr.Alias)).Select(x => x.Id);
|
||||
|
||||
// merge ids
|
||||
var ids = oth.Concat(new[] { clr.Id }).ToArray();
|
||||
|
||||
// clear them all at once
|
||||
// we don't support "clear many at once" at the moment - so, cheating
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
|
||||
(key, value) => value.Id == id);
|
||||
(key, value) => ids.Contains(value.Id));
|
||||
}
|
||||
|
||||
internal static void ClearDataType(int id)
|
||||
|
||||
@@ -164,6 +164,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
private void InitializeConverters()
|
||||
{
|
||||
//TODO: Look at optimizing this method, it gets run for every property type for the document being rendered at startup,
|
||||
// every precious second counts!
|
||||
|
||||
var converters = PropertyValueConvertersResolver.Current.Converters.ToArray();
|
||||
var defaultConvertersWithAttributes = PropertyValueConvertersResolver.Current.DefaultConverters;
|
||||
|
||||
@@ -230,13 +233,13 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
_sourceCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
_xpathCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
_xpathCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
}
|
||||
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
|
||||
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Name = typeDto.Name,
|
||||
SortOrder = typeDto.SortOrder,
|
||||
ValidationRegExp = typeDto.ValidationRegExp,
|
||||
PropertyGroupId = new Lazy<int>(() => default(int)),
|
||||
PropertyGroupId = null,
|
||||
CreateDate = dto.CreateDate,
|
||||
UpdateDate = dto.CreateDate
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -27,18 +28,21 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
private readonly IMigration[] _migrations;
|
||||
|
||||
[Obsolete("Use the ctor that specifies all dependencies instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationRunner(Version currentVersion, Version targetVersion, string productName)
|
||||
: this(LoggerResolver.Current.Logger, currentVersion, targetVersion, productName)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the ctor that specifies all dependencies instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationRunner(ILogger logger, Version currentVersion, Version targetVersion, string productName)
|
||||
: this(logger, currentVersion, targetVersion, productName, null)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the ctor that specifies all dependencies instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationRunner(ILogger logger, Version currentVersion, Version targetVersion, string productName, params IMigration[] migrations)
|
||||
: this(ApplicationContext.Current.Services.MigrationEntryService, logger, new SemVersion(currentVersion), new SemVersion(targetVersion), productName, migrations)
|
||||
{
|
||||
@@ -92,7 +96,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
: OrderedDowngradeMigrations(foundMigrations).ToList();
|
||||
|
||||
|
||||
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, true), this))
|
||||
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, _productName, true), this))
|
||||
{
|
||||
_logger.Warn<MigrationRunner>("Migration was cancelled by an event");
|
||||
return false;
|
||||
@@ -121,7 +125,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
throw;
|
||||
}
|
||||
|
||||
Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, false), this);
|
||||
Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, _productName, false), this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -289,7 +293,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
//NOTE: We CANNOT do this as part of the transaction!!! This is because when upgrading to 7.3, we cannot
|
||||
// create the migrations table and then add data to it in the same transaction without issuing things like GO
|
||||
// commands and since we need to support all Dbs, we need to just do this after the fact.
|
||||
var exists = _migrationEntryService.FindEntry(GlobalSettings.UmbracoMigrationName, _targetVersion);
|
||||
var exists = _migrationEntryService.FindEntry(_productName, _targetVersion);
|
||||
if (exists == null)
|
||||
{
|
||||
_migrationEntryService.CreateEntry(_productName, _targetVersion);
|
||||
@@ -308,4 +312,4 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<MigrationRunner, MigrationEventArgs> Migrated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -37,9 +37,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
|
||||
if (!dataTypeIds.Any()) return string.Empty;
|
||||
|
||||
var propertyData =
|
||||
database.Fetch<PropertyDataDto>(
|
||||
"WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds });
|
||||
// need to use dynamic, as PropertyDataDto has new properties
|
||||
var propertyData = database.Fetch<dynamic>("SELECT * FROM cmsPropertyData"
|
||||
+ " WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds });
|
||||
if (!propertyData.Any()) return string.Empty;
|
||||
|
||||
var nodesIdsWithProperty = propertyData.Select(x => x.NodeId).Distinct().ToArray();
|
||||
@@ -71,13 +71,16 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
xml = new XmlDocument();
|
||||
xml.LoadXml(data.Text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error<UpdateRelatedLinksData>("The data stored for property id " + data.Id + " on document " + data.NodeId +
|
||||
" is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + data.Text, ex);
|
||||
int dataId = data.id;
|
||||
int dataNodeId = data.nodeId;
|
||||
string dataText = data.dataNText;
|
||||
Logger.Error<UpdateRelatedLinksData>("The data stored for property id " + dataId + " on document " + dataNodeId +
|
||||
" is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + dataText, ex);
|
||||
|
||||
data.Text = "";
|
||||
database.Update(data);
|
||||
data.dataNText = "";
|
||||
database.Update("cmsPropertyData", "id", data, new[] { "dataNText" });
|
||||
|
||||
UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database);
|
||||
|
||||
@@ -91,11 +94,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
{
|
||||
var title = node.Attributes["title"].Value;
|
||||
var type = node.Attributes["type"].Value;
|
||||
var newwindow = node.Attributes["newwindow"].Value.Equals("1") ? true : false;
|
||||
var newwindow = node.Attributes["newwindow"].Value.Equals("1");
|
||||
var lnk = node.Attributes["link"].Value;
|
||||
|
||||
//create the links in the format the new prop editor expects it to be
|
||||
var link = new ExpandoObject() as IDictionary<string, Object>;
|
||||
var link = new ExpandoObject() as IDictionary<string, object>;
|
||||
link.Add("title", title);
|
||||
link.Add("caption", title);
|
||||
link.Add("link", lnk);
|
||||
@@ -110,9 +113,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
}
|
||||
|
||||
//store the serialized data
|
||||
data.Text = JsonConvert.SerializeObject(links);
|
||||
data.dataNText = JsonConvert.SerializeObject(links);
|
||||
|
||||
database.Update(data);
|
||||
database.Update("cmsPropertyData", "id", data, new[] { "dataNText" });
|
||||
|
||||
UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database);
|
||||
|
||||
|
||||
+43
-29
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -33,45 +35,57 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourZer
|
||||
|
||||
// fill in the data in a way that is consistent over all environments
|
||||
// (ie cannot use random guids, http://issues.umbraco.org/issue/U4-6942)
|
||||
Execute.Code(UpdateGuids);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var data in Context.Database.Query<dynamic>(@"
|
||||
private static string UpdateGuids(Database database)
|
||||
{
|
||||
var updates = new List<Tuple<Guid, int>>();
|
||||
|
||||
foreach (var data in database.Query<dynamic>(@"
|
||||
SELECT cmsPropertyTypeGroup.id grId, cmsPropertyTypeGroup.text grName, cmsContentType.alias ctAlias, umbracoNode.nodeObjectType nObjType
|
||||
FROM cmsPropertyTypeGroup
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsPropertyTypeGroup.contentTypeNodeId = cmsContentType.nodeId
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id"))
|
||||
{
|
||||
Guid guid;
|
||||
// see BaseDataCreation... built-in groups have their own guids
|
||||
if (data.grId == 3)
|
||||
{
|
||||
Guid guid;
|
||||
// see BaseDataCreation... built-in groups have their own guids
|
||||
if (data.grId == 3)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Image);
|
||||
}
|
||||
else if (data.grId == 4)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.File);
|
||||
}
|
||||
else if (data.grId == 5)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Contents);
|
||||
}
|
||||
else if (data.grId == 11)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Membership);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a consistent guid from
|
||||
// group name + content type alias + object type
|
||||
string guidSource = data.grName + data.ctAlias + data.nObjType;
|
||||
guid = guidSource.ToGuid();
|
||||
}
|
||||
|
||||
// set the Unique Id to the one we've generated
|
||||
Update.Table("cmsPropertyTypeGroup").Set(new { uniqueID = guid }).Where(new { id = data.grId });
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Image);
|
||||
}
|
||||
else if (data.grId == 4)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.File);
|
||||
}
|
||||
else if (data.grId == 5)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Contents);
|
||||
}
|
||||
else if (data.grId == 11)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Membership);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a consistent guid from
|
||||
// group name + content type alias + object type
|
||||
string guidSource = data.grName + data.ctAlias + data.nObjType;
|
||||
guid = guidSource.ToGuid();
|
||||
}
|
||||
|
||||
// set the Unique Id to the one we've generated
|
||||
// but not within the foreach loop (as we already have a data reader open)
|
||||
updates.Add(Tuple.Create(guid, data.grId));
|
||||
}
|
||||
|
||||
foreach (var update in updates)
|
||||
database.Execute("UPDATE cmsPropertyTypeGroup SET uniqueID=@uid WHERE id=@id", new { uid = update.Item1, id = update.Item2 });
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
|
||||
+11
-1
@@ -20,7 +20,17 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourZer
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("cmsPropertyTypeGroup") && x.ColumnName.InvariantEquals("parentGroupId")) == false)
|
||||
return;
|
||||
|
||||
Delete.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id").OnTable("cmsPropertyTypeGroup");
|
||||
//This constraing can be based on old aliases, before removing them, check they exist
|
||||
var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("cmsPropertyTypeGroup") && x.Item3.InvariantEquals("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id")))
|
||||
{
|
||||
Delete.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id").OnTable("cmsPropertyTypeGroup");
|
||||
}
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("cmsPropertyTypeGroup") && x.Item3.InvariantEquals("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup")))
|
||||
{
|
||||
Delete.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup").OnTable("cmsPropertyTypeGroup");
|
||||
}
|
||||
|
||||
Delete.Column("parentGroupId").FromTable("cmsPropertyTypeGroup");
|
||||
}
|
||||
|
||||
|
||||
+25
-13
@@ -33,36 +33,40 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
// won't exist yet
|
||||
var propertyTypes = database.Fetch<dynamic>("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
|
||||
|
||||
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
|
||||
// need to use dynamic, as PropertyTypeGroupDto has new properties
|
||||
var propertyGroups = database.Fetch<dynamic>("SELECT * FROM cmsPropertyTypeGroup WHERE id > 0");
|
||||
|
||||
foreach (var propertyType in propertyTypes)
|
||||
{
|
||||
// get the PropertyTypeGroup of the current PropertyType, skip if not found
|
||||
var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.propertyTypeGroupId);
|
||||
var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.id == propertyType.propertyTypeGroupId);
|
||||
if (propertyTypeGroup == null) continue;
|
||||
|
||||
// if the PropretyTypeGroup belongs to the same content type as the PropertyType, then fine
|
||||
if (propertyTypeGroup.ContentTypeNodeId == propertyType.contentTypeId) continue;
|
||||
if (propertyTypeGroup.contenttypeNodeId == propertyType.contentTypeId) continue;
|
||||
|
||||
// else we want to assign the PropertyType to a proper PropertyTypeGroup
|
||||
// ie one that does belong to the same content - look for it
|
||||
var okPropertyTypeGroup = propertyGroups.FirstOrDefault(x =>
|
||||
x.Text == propertyTypeGroup.Text && // same name
|
||||
x.ContentTypeNodeId == propertyType.contentTypeId); // but for proper content type
|
||||
x.text == propertyTypeGroup.text && // same name
|
||||
x.contenttypeNodeId == propertyType.contentTypeId); // but for proper content type
|
||||
|
||||
if (okPropertyTypeGroup == null)
|
||||
{
|
||||
// does not exist, create a new PropertyTypeGroup,
|
||||
var propertyGroup = new PropertyTypeGroupDto
|
||||
// does not exist, create a new PropertyTypeGroup
|
||||
// cannot use a PropertyTypeGroupDto because of the new (not-yet-existing) uniqueID property
|
||||
// cannot use a dynamic because database.Insert fails to set the value of property
|
||||
var propertyGroup = new PropertyTypeGroupDtoTemp
|
||||
{
|
||||
ContentTypeNodeId = propertyType.contentTypeId,
|
||||
Text = propertyTypeGroup.Text,
|
||||
SortOrder = propertyTypeGroup.SortOrder
|
||||
id = 0,
|
||||
contenttypeNodeId = propertyType.contentTypeId,
|
||||
text = propertyTypeGroup.text,
|
||||
sortorder = propertyTypeGroup.sortorder
|
||||
};
|
||||
|
||||
// save + add to list of groups
|
||||
int id = Convert.ToInt16(database.Insert(propertyGroup));
|
||||
propertyGroup.Id = id;
|
||||
int id = Convert.ToInt16(database.Insert("cmsPropertyTypeGroup", "id", propertyGroup));
|
||||
propertyGroup.id = id;
|
||||
propertyGroups.Add(propertyGroup);
|
||||
|
||||
// update the PropertyType to use the new PropertyTypeGroup
|
||||
@@ -71,7 +75,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
else
|
||||
{
|
||||
// exists, update PropertyType to use the PropertyTypeGroup
|
||||
propertyType.propertyTypeGroupId = okPropertyTypeGroup.Id;
|
||||
propertyType.propertyTypeGroupId = okPropertyTypeGroup.id;
|
||||
}
|
||||
database.Update("cmsPropertyType", "id", propertyType);
|
||||
}
|
||||
@@ -79,5 +83,13 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private class PropertyTypeGroupDtoTemp
|
||||
{
|
||||
public int id { get; set; }
|
||||
public int contenttypeNodeId { get; set; }
|
||||
public string text { get; set; }
|
||||
public int sortorder { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -834,7 +834,7 @@ namespace Umbraco.Core.Persistence
|
||||
var pd = PocoData.ForType(typeof(T));
|
||||
try
|
||||
{
|
||||
r = cmd.ExecuteReader();
|
||||
r = cmd.ExecuteReaderWithRetry();
|
||||
OnExecutedCommand(cmd);
|
||||
}
|
||||
catch (Exception x)
|
||||
|
||||
@@ -128,6 +128,34 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
}
|
||||
else if (operand == "=")
|
||||
{
|
||||
// deal with (x == true|false) - most common
|
||||
var constRight = b.Right as ConstantExpression;
|
||||
if (constRight != null && constRight.Type == typeof (bool))
|
||||
return ((bool) constRight.Value) ? VisitNotNot(b.Left) : VisitNot(b.Left);
|
||||
right = Visit(b.Right);
|
||||
|
||||
// deal with (true|false == x) - why not
|
||||
var constLeft = b.Left as ConstantExpression;
|
||||
if (constLeft != null && constLeft.Type == typeof (bool))
|
||||
return ((bool) constLeft.Value) ? VisitNotNot(b.Right) : VisitNot(b.Right);
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
else if (operand == "<>")
|
||||
{
|
||||
// deal with (x != true|false) - most common
|
||||
var constRight = b.Right as ConstantExpression;
|
||||
if (constRight != null && constRight.Type == typeof(bool))
|
||||
return ((bool) constRight.Value) ? VisitNot(b.Left) : VisitNotNot(b.Left);
|
||||
right = Visit(b.Right);
|
||||
|
||||
// deal with (true|false != x) - why not
|
||||
var constLeft = b.Left as ConstantExpression;
|
||||
if (constLeft != null && constLeft.Type == typeof(bool))
|
||||
return ((bool) constLeft.Value) ? VisitNot(b.Right) : VisitNotNot(b.Right);
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
@@ -152,7 +180,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
case "COALESCE":
|
||||
return string.Format("{0}({1},{2})", operand, left, right);
|
||||
default:
|
||||
return left + " " + operand + " " + right;
|
||||
return "(" + left + " " + operand + " " + right + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,25 +259,47 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
switch (u.NodeType)
|
||||
{
|
||||
case ExpressionType.Not:
|
||||
var o = Visit(u.Operand);
|
||||
|
||||
//use a Not equal operator instead of <> since we don't know that <> works in all sql servers
|
||||
|
||||
switch (u.Operand.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
//In this case it wil be a false property , i.e. x => !Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("NOT ({0} = @0)", o);
|
||||
default:
|
||||
//In this case it could be anything else, such as: x => !x.Path.StartsWith("-20")
|
||||
return string.Format("NOT ({0})", o);
|
||||
}
|
||||
return VisitNot(u.Operand);
|
||||
default:
|
||||
return Visit(u.Operand);
|
||||
}
|
||||
}
|
||||
|
||||
private string VisitNot(Expression exp)
|
||||
{
|
||||
var o = Visit(exp);
|
||||
|
||||
// use a "NOT (...)" syntax instead of "<>" since we don't know whether "<>" works in all sql servers
|
||||
// also, x.StartsWith(...) translates to "x LIKE '...%'" which we cannot "<>" and have to "NOT (...")
|
||||
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
// false property , i.e. x => !Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("NOT ({0} = @{1})", o, SqlParameters.Count - 1);
|
||||
default:
|
||||
// could be anything else, such as: x => !x.Path.StartsWith("-20")
|
||||
return "NOT (" + o + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private string VisitNotNot(Expression exp)
|
||||
{
|
||||
var o = Visit(exp);
|
||||
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
// true property, i.e. x => Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("({0} = @{1})", o, SqlParameters.Count - 1);
|
||||
default:
|
||||
// could be anything else, such as: x => x.Path.StartsWith("-20")
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
|
||||
|
||||
@@ -18,8 +18,11 @@ namespace Umbraco.Core.Persistence.Relators
|
||||
// Is this the same DictionaryItem as the current one we're processing
|
||||
if (Current != null && Current.Id == a.Id)
|
||||
{
|
||||
// Yes, just add this User2AppDto to the current item's collection
|
||||
Current.User2AppDtos.Add(p);
|
||||
if (p.AppAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
// Yes, just add this User2AppDto to the current item's collection
|
||||
Current.User2AppDtos.Add(p);
|
||||
}
|
||||
|
||||
// Return null to indicate we're not done with this User yet
|
||||
return null;
|
||||
@@ -35,7 +38,7 @@ namespace Umbraco.Core.Persistence.Relators
|
||||
Current = a;
|
||||
Current.User2AppDtos = new List<User2AppDto>();
|
||||
//this can be null since we are doing a left join
|
||||
if (p.AppAlias != null)
|
||||
if (p.AppAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
Current.User2AppDtos.Add(p);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
"DELETE FROM cmsContentXml WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsContent WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoAccess WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
};
|
||||
return list;
|
||||
}
|
||||
@@ -689,8 +689,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public int CountPublished()
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true)
|
||||
.Where<DocumentDto>(x => x.Newest == true);
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<MoveEventInfo<TEntity>> Move(TEntity toMove, EntityContainer container)
|
||||
{
|
||||
var parentId = -1;
|
||||
var parentId = Constants.System.Root;
|
||||
if (container != null)
|
||||
{
|
||||
// Check on paths
|
||||
@@ -54,38 +54,36 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
new MoveEventInfo<TEntity>(toMove, toMove.Path, parentId)
|
||||
};
|
||||
|
||||
var origPath = toMove.Path;
|
||||
|
||||
//do the move to a new parent
|
||||
// get the level delta (old pos to new pos)
|
||||
var levelDelta = container == null
|
||||
? 1 - toMove.Level
|
||||
: container.Level + 1 - toMove.Level;
|
||||
|
||||
// move to parent (or -1), update path, save
|
||||
toMove.ParentId = parentId;
|
||||
|
||||
//set the updated path
|
||||
toMove.Path = string.Concat(container == null ? parentId.ToInvariantString() : container.Path, ",", toMove.Id);
|
||||
|
||||
//schedule it for updating in the transaction
|
||||
var toMovePath = toMove.Path + ","; // save before changing
|
||||
toMove.Path = (container == null ? Constants.System.Root.ToString() : container.Path) + "," + toMove.Id;
|
||||
toMove.Level = container == null ? 1 : container.Level + 1;
|
||||
AddOrUpdate(toMove);
|
||||
|
||||
//update all descendants, update in order of level
|
||||
var descendants = this.GetByQuery(
|
||||
new Query<TEntity>().Where(type => type.Path.StartsWith(origPath + ",")));
|
||||
var descendants = GetByQuery(new Query<TEntity>().Where(type => type.Path.StartsWith(toMovePath)));
|
||||
var paths = new Dictionary<int, string>();
|
||||
paths[toMove.Id] = toMove.Path;
|
||||
|
||||
var lastParent = toMove;
|
||||
foreach (var descendant in descendants.OrderBy(x => x.Level))
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<TEntity>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
descendant.ParentId = lastParent.Id;
|
||||
descendant.Path = string.Concat(lastParent.Path, ",", descendant.Id);
|
||||
descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
|
||||
descendant.Level += levelDelta;
|
||||
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(descendant);
|
||||
|
||||
lastParent = descendant;
|
||||
}
|
||||
|
||||
return moveInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content type ids that match the query
|
||||
/// </summary>
|
||||
@@ -287,7 +285,7 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
//Find PropertyTypes for the removed ContentType
|
||||
var propertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = key });
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//based on the PropertyTypes that belong to the removed ContentType.
|
||||
foreach (var contentDto in contentDtos)
|
||||
{
|
||||
@@ -411,7 +409,7 @@ AND umbracoNode.id <> @id",
|
||||
AssignDataTypeFromPropertyEditor(propertyType);
|
||||
}
|
||||
|
||||
//validate the alias!
|
||||
//validate the alias!
|
||||
ValidateAlias(propertyType);
|
||||
|
||||
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType);
|
||||
@@ -585,14 +583,13 @@ AND umbracoNode.id <> @id",
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IMediaType> GetMediaTypes<TRepo, TId>(
|
||||
TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
public static IEnumerable<IMediaType> GetMediaTypes<TRepo>(
|
||||
Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
TRepo contentTypeRepository)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId: struct
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
IDictionary<TId, IEnumerable<TId>> allParentMediaTypeIds;
|
||||
var mediaTypes = MapMediaTypes(mediaTypeIds, db, sqlSyntax, out allParentMediaTypeIds)
|
||||
IDictionary<int, List<int>> allParentMediaTypeIds;
|
||||
var mediaTypes = MapMediaTypes(db, sqlSyntax, out allParentMediaTypeIds)
|
||||
.ToArray();
|
||||
|
||||
MapContentTypeChildren(mediaTypes, db, sqlSyntax, contentTypeRepository, allParentMediaTypeIds);
|
||||
@@ -600,16 +597,15 @@ AND umbracoNode.id <> @id",
|
||||
return mediaTypes;
|
||||
}
|
||||
|
||||
public static IEnumerable<IContentType> GetContentTypes<TRepo, TId>(
|
||||
TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
public static IEnumerable<IContentType> GetContentTypes<TRepo>(
|
||||
Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
TRepo contentTypeRepository,
|
||||
ITemplateRepository templateRepository)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId : struct
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
IDictionary<TId, IEnumerable<AssociatedTemplate>> allAssociatedTemplates;
|
||||
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds;
|
||||
var contentTypes = MapContentTypes(contentTypeIds, db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
|
||||
IDictionary<int, List<AssociatedTemplate>> allAssociatedTemplates;
|
||||
IDictionary<int, List<int>> allParentContentTypeIds;
|
||||
var contentTypes = MapContentTypes(db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
|
||||
.ToArray();
|
||||
|
||||
if (contentTypes.Any())
|
||||
@@ -624,12 +620,11 @@ AND umbracoNode.id <> @id",
|
||||
return contentTypes;
|
||||
}
|
||||
|
||||
internal static void MapContentTypeChildren<TRepo, TId>(IContentTypeComposition[] contentTypes,
|
||||
internal static void MapContentTypeChildren<TRepo>(IContentTypeComposition[] contentTypes,
|
||||
Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
TRepo contentTypeRepository,
|
||||
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId : struct
|
||||
IDictionary<int, List<int>> allParentContentTypeIds)
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
//NOTE: SQL call #2
|
||||
|
||||
@@ -651,25 +646,22 @@ AND umbracoNode.id <> @id",
|
||||
var allParentIdsAsArray = allParentContentTypeIds.SelectMany(x => x.Value).Distinct().ToArray();
|
||||
if (allParentIdsAsArray.Any())
|
||||
{
|
||||
var allParentContentTypes = contentTypeRepository.GetAll(allParentIdsAsArray).ToArray();
|
||||
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
|
||||
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
|
||||
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
|
||||
{
|
||||
var entityId = contentType.Id;
|
||||
|
||||
var parentContentTypes = allParentContentTypes.Where(x =>
|
||||
{
|
||||
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
|
||||
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
|
||||
var parentEntityId = typeof(TId) == typeof(int) ? x.Id : (object)x.Key;
|
||||
var parentEntityId = x.Id;
|
||||
|
||||
return allParentContentTypeIds[(TId)entityId].Contains((TId)parentEntityId);
|
||||
return allParentContentTypeIds[entityId].Contains(parentEntityId);
|
||||
});
|
||||
foreach (var parentContentType in parentContentTypes)
|
||||
{
|
||||
var result = contentType.AddContentType(parentContentType);
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
|
||||
}
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
@@ -682,13 +674,12 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
}
|
||||
|
||||
internal static void MapContentTypeTemplates<TRepo, TId>(IContentType[] contentTypes,
|
||||
internal static void MapContentTypeTemplates<TRepo>(IContentType[] contentTypes,
|
||||
Database db,
|
||||
TRepo contentTypeRepository,
|
||||
ITemplateRepository templateRepository,
|
||||
IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId: struct
|
||||
IDictionary<int, List<AssociatedTemplate>> associatedTemplates)
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
if (associatedTemplates == null || associatedTemplates.Any() == false) return;
|
||||
|
||||
@@ -705,11 +696,9 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
|
||||
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
|
||||
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
|
||||
|
||||
var associatedTemplateIds = associatedTemplates[(TId)entityId].Select(x => x.TemplateId)
|
||||
var entityId = contentType.Id;
|
||||
|
||||
var associatedTemplateIds = associatedTemplates[entityId].Select(x => x.TemplateId)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
@@ -721,19 +710,14 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
}
|
||||
|
||||
internal static IEnumerable<IMediaType> MapMediaTypes<TId>(TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<TId, IEnumerable<TId>> parentMediaTypeIds)
|
||||
where TId : struct
|
||||
internal static IEnumerable<IMediaType> MapMediaTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<int, List<int>> parentMediaTypeIds)
|
||||
{
|
||||
Mandate.That(mediaTypeIds.Any(), () => new InvalidOperationException("must be at least one content type id specified"));
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
//ensure they are unique
|
||||
mediaTypeIds = mediaTypeIds.Distinct().ToArray();
|
||||
|
||||
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
@@ -742,40 +726,23 @@ AND umbracoNode.id <> @id",
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
ON AllowedTypes.Id = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
|
||||
|
||||
if (mediaTypeIds.Any())
|
||||
{
|
||||
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
|
||||
// work for the time being.
|
||||
if (typeof(TId) == typeof(int))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
|
||||
}
|
||||
else if (typeof(TId) == typeof(Guid))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
|
||||
if ((mediaTypeIds.Length - 1) > 2000)
|
||||
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType), contentTypeIds = mediaTypeIds });
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType) });
|
||||
|
||||
if (result.Any() == false)
|
||||
{
|
||||
@@ -783,95 +750,118 @@ AND umbracoNode.id <> @id",
|
||||
return Enumerable.Empty<IMediaType>();
|
||||
}
|
||||
|
||||
parentMediaTypeIds = new Dictionary<TId, IEnumerable<TId>>();
|
||||
parentMediaTypeIds = new Dictionary<int, List<int>>();
|
||||
var mappedMediaTypes = new List<IMediaType>();
|
||||
|
||||
foreach (var contentTypeId in mediaTypeIds)
|
||||
//loop through each result and fill in our required values, each row will contain different requried data than the rest.
|
||||
// it is much quicker to iterate each result and populate instead of looking up the values over and over in the result like
|
||||
// we used to do.
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
//the current content type id that we're working with
|
||||
var ct = queue.Dequeue();
|
||||
|
||||
var currentCtId = contentTypeId;
|
||||
|
||||
//first we want to get the main content type data this is 1 : 1 with umbraco node data
|
||||
|
||||
var ct = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof (TId) == typeof (int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
|
||||
.DistinctBy(x => (int)x.ctId)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (ct == null)
|
||||
//check for allowed content types
|
||||
int? allowedCtId = ct.ctaAllowedId;
|
||||
int? allowedCtSort = ct.ctaSortOrder;
|
||||
string allowedCtAlias = ct.ctaAlias;
|
||||
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
|
||||
{
|
||||
continue;
|
||||
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
|
||||
if (currAllowedContentTypes.Contains(ctSort) == false)
|
||||
{
|
||||
currAllowedContentTypes.Add(ctSort);
|
||||
}
|
||||
}
|
||||
|
||||
var contentTypeDto = new ContentTypeDto
|
||||
//always ensure there's a list for this content type
|
||||
if (parentMediaTypeIds.ContainsKey(ct.ctId) == false)
|
||||
parentMediaTypeIds[ct.ctId] = new List<int>();
|
||||
|
||||
//check for parent ids and assign to the outgoing collection
|
||||
int? parentId = ct.chtParentId;
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
Alias = ct.ctAlias,
|
||||
AllowAtRoot = ct.ctAllowAtRoot,
|
||||
Description = ct.ctDesc,
|
||||
Icon = ct.ctIcon,
|
||||
IsContainer = ct.ctIsContainer,
|
||||
NodeId = ct.ctId,
|
||||
PrimaryKey = ct.ctPk,
|
||||
Thumbnail = ct.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = ct.nCreateDate,
|
||||
Level = (short)ct.nLevel,
|
||||
NodeId = ct.ctId,
|
||||
NodeObjectType = ct.nObjectType,
|
||||
ParentId = ct.nParentId,
|
||||
Path = ct.nPath,
|
||||
SortOrder = ct.nSortOrder,
|
||||
Text = ct.nName,
|
||||
Trashed = ct.nTrashed,
|
||||
UniqueId = ct.nUniqueId,
|
||||
UserId = ct.nUser
|
||||
}
|
||||
};
|
||||
var associatedParentIds = parentMediaTypeIds[ct.ctId];
|
||||
if (associatedParentIds.Contains(parentId.Value) == false)
|
||||
associatedParentIds.Add(parentId.Value);
|
||||
}
|
||||
|
||||
//now create the media type object
|
||||
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
|
||||
{
|
||||
//it's the last in the queue or the content type is changing (moving to the next one)
|
||||
var mediaType = CreateForMapping(ct, currAllowedContentTypes);
|
||||
mappedMediaTypes.Add(mediaType);
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var mediaType = factory.BuildMediaTypeEntity(contentTypeDto);
|
||||
|
||||
//map the allowed content types
|
||||
//map the child content type ids
|
||||
MapCommonContentTypeObjects(mediaType, currentCtId, result, parentMediaTypeIds);
|
||||
|
||||
mappedMediaTypes.Add(mediaType);
|
||||
//Here we need to reset the current variables, we're now collecting data for a different content type
|
||||
currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
}
|
||||
}
|
||||
|
||||
return mappedMediaTypes;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IContentType> MapContentTypes<TId>(TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates,
|
||||
out IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
|
||||
where TId : struct
|
||||
private static IMediaType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes)
|
||||
{
|
||||
// * create the DTO object
|
||||
// * create the content type object
|
||||
// * map the allowed content types
|
||||
// * add to the outgoing list
|
||||
|
||||
var contentTypeDto = new ContentTypeDto
|
||||
{
|
||||
Alias = currCt.ctAlias,
|
||||
AllowAtRoot = currCt.ctAllowAtRoot,
|
||||
Description = currCt.ctDesc,
|
||||
Icon = currCt.ctIcon,
|
||||
IsContainer = currCt.ctIsContainer,
|
||||
NodeId = currCt.ctId,
|
||||
PrimaryKey = currCt.ctPk,
|
||||
Thumbnail = currCt.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = currCt.nCreateDate,
|
||||
Level = (short)currCt.nLevel,
|
||||
NodeId = currCt.ctId,
|
||||
NodeObjectType = currCt.nObjectType,
|
||||
ParentId = currCt.nParentId,
|
||||
Path = currCt.nPath,
|
||||
SortOrder = currCt.nSortOrder,
|
||||
Text = currCt.nName,
|
||||
Trashed = currCt.nTrashed,
|
||||
UniqueId = currCt.nUniqueId,
|
||||
UserId = currCt.nUser
|
||||
}
|
||||
};
|
||||
|
||||
//now create the content type object
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var mediaType = factory.BuildMediaTypeEntity(contentTypeDto);
|
||||
|
||||
//map the allowed content types
|
||||
mediaType.AllowedContentTypes = currAllowedContentTypes;
|
||||
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IContentType> MapContentTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<int, List<AssociatedTemplate>> associatedTemplates,
|
||||
out IDictionary<int, List<int>> parentContentTypeIds)
|
||||
{
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
//ensure they are unique
|
||||
contentTypeIds = contentTypeIds.Distinct().ToArray();
|
||||
|
||||
|
||||
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
Template.alias as tAlias, Template.nodeId as tId,Template.text as tText
|
||||
FROM cmsContentType
|
||||
INNER JOIN umbracoNode
|
||||
@@ -879,8 +869,8 @@ AND umbracoNode.id <> @id",
|
||||
LEFT JOIN cmsDocumentType
|
||||
ON cmsDocumentType.contentTypeNodeId = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
@@ -893,33 +883,15 @@ AND umbracoNode.id <> @id",
|
||||
ON Template.nodeId = cmsDocumentType.templateNodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
|
||||
|
||||
if (contentTypeIds.Any())
|
||||
{
|
||||
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
|
||||
// work for the time being.
|
||||
if (typeof(TId) == typeof(int))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
|
||||
}
|
||||
else if (typeof(TId) == typeof(Guid))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
|
||||
if ((contentTypeIds.Length - 1) > 2000)
|
||||
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), contentTypeIds = contentTypeIds });
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType)});
|
||||
|
||||
if (result.Any() == false)
|
||||
{
|
||||
@@ -928,170 +900,139 @@ AND umbracoNode.id <> @id",
|
||||
return Enumerable.Empty<IContentType>();
|
||||
}
|
||||
|
||||
parentContentTypeIds = new Dictionary<TId, IEnumerable<TId>>();
|
||||
associatedTemplates = new Dictionary<TId, IEnumerable<AssociatedTemplate>>();
|
||||
parentContentTypeIds = new Dictionary<int, List<int>>();
|
||||
associatedTemplates = new Dictionary<int, List<AssociatedTemplate>>();
|
||||
var mappedContentTypes = new List<IContentType>();
|
||||
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var currDefaultTemplate = -1;
|
||||
var currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
//the current content type id that we're working with
|
||||
var ct = queue.Dequeue();
|
||||
|
||||
var currentCtId = contentTypeId;
|
||||
|
||||
//first we want to get the main content type data this is 1 : 1 with umbraco node data
|
||||
|
||||
var ct = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
|
||||
.DistinctBy(x => (int)x.ctId)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (ct == null)
|
||||
//check for default templates
|
||||
bool? isDefaultTemplate = Convert.ToBoolean(ct.dtIsDefault);
|
||||
int? templateId = ct.dtTemplateId;
|
||||
if (currDefaultTemplate == -1 && isDefaultTemplate.HasValue && isDefaultTemplate.Value && templateId.HasValue)
|
||||
{
|
||||
continue;
|
||||
currDefaultTemplate = templateId.Value;
|
||||
}
|
||||
|
||||
//get the unique list of associated templates
|
||||
var defaultTemplates = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
//use a tuple so that distinct checks both values (in some rare cases the dtIsDefault will not compute as bool?, so we force it with Convert.ToBoolean)
|
||||
.Select(x => new Tuple<bool?, int?>(Convert.ToBoolean(x.dtIsDefault), x.dtTemplateId))
|
||||
.Where(x => x.Item1.HasValue && x.Item2.HasValue)
|
||||
.Distinct()
|
||||
.OrderByDescending(x => x.Item1.Value)
|
||||
.ToArray();
|
||||
//if there isn't one set to default explicitly, we'll pick the first one
|
||||
var defaultTemplate = defaultTemplates.FirstOrDefault(x => x.Item1.Value)
|
||||
?? defaultTemplates.FirstOrDefault();
|
||||
//always ensure there's a list for this content type
|
||||
if (associatedTemplates.ContainsKey(ct.ctId) == false)
|
||||
associatedTemplates[ct.ctId] = new List<AssociatedTemplate>();
|
||||
|
||||
var dtDto = new ContentTypeTemplateDto
|
||||
//check for associated templates and assign to the outgoing collection
|
||||
if (ct.tId != null)
|
||||
{
|
||||
//create the content type dto
|
||||
ContentTypeDto = new ContentTypeDto
|
||||
var associatedTemplate = new AssociatedTemplate(ct.tId, ct.tAlias, ct.tText);
|
||||
var associatedList = associatedTemplates[ct.ctId];
|
||||
|
||||
if (associatedList.Contains(associatedTemplate) == false)
|
||||
associatedList.Add(associatedTemplate);
|
||||
}
|
||||
|
||||
//check for allowed content types
|
||||
int? allowedCtId = ct.ctaAllowedId;
|
||||
int? allowedCtSort = ct.ctaSortOrder;
|
||||
string allowedCtAlias = ct.ctaAlias;
|
||||
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
|
||||
{
|
||||
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
|
||||
if (currAllowedContentTypes.Contains(ctSort) == false)
|
||||
{
|
||||
Alias = ct.ctAlias,
|
||||
AllowAtRoot = ct.ctAllowAtRoot,
|
||||
Description = ct.ctDesc,
|
||||
Icon = ct.ctIcon,
|
||||
IsContainer = ct.ctIsContainer,
|
||||
NodeId = ct.ctId,
|
||||
PrimaryKey = ct.ctPk,
|
||||
Thumbnail = ct.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = ct.nCreateDate,
|
||||
Level = (short)ct.nLevel,
|
||||
NodeId = ct.ctId,
|
||||
NodeObjectType = ct.nObjectType,
|
||||
ParentId = ct.nParentId,
|
||||
Path = ct.nPath,
|
||||
SortOrder = ct.nSortOrder,
|
||||
Text = ct.nName,
|
||||
Trashed = ct.nTrashed,
|
||||
UniqueId = ct.nUniqueId,
|
||||
UserId = ct.nUser
|
||||
}
|
||||
},
|
||||
ContentTypeNodeId = ct.ctId,
|
||||
IsDefault = defaultTemplate != null,
|
||||
TemplateNodeId = defaultTemplate != null ? defaultTemplate.Item2.Value : 0,
|
||||
};
|
||||
currAllowedContentTypes.Add(ctSort);
|
||||
}
|
||||
}
|
||||
|
||||
// We will map a subset of the associated template - alias, id, name
|
||||
//always ensure there's a list for this content type
|
||||
if (parentContentTypeIds.ContainsKey(ct.ctId) == false)
|
||||
parentContentTypeIds[ct.ctId] = new List<int>();
|
||||
|
||||
associatedTemplates.Add(currentCtId, result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Where(x => x.tId != null)
|
||||
.Select(x => new AssociatedTemplate(x.tId, x.tAlias, x.tText))
|
||||
.Distinct()
|
||||
.ToArray());
|
||||
//check for parent ids and assign to the outgoing collection
|
||||
int? parentId = ct.chtParentId;
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
var associatedParentIds = parentContentTypeIds[ct.ctId];
|
||||
|
||||
//now create the content type object
|
||||
if (associatedParentIds.Contains(parentId.Value) == false)
|
||||
associatedParentIds.Add(parentId.Value);
|
||||
}
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var contentType = factory.BuildContentTypeEntity(dtDto.ContentTypeDto);
|
||||
|
||||
// NOTE
|
||||
// that was done by the factory but makes little sense, moved here, so
|
||||
// now we have to reset dirty props again (as the factory does it) and yet,
|
||||
// we are not managing allowed templates... the whole thing is weird.
|
||||
((ContentType) contentType).DefaultTemplateId = dtDto.TemplateNodeId;
|
||||
contentType.ResetDirtyProperties(false);
|
||||
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
|
||||
{
|
||||
//it's the last in the queue or the content type is changing (moving to the next one)
|
||||
var contentType = CreateForMapping(ct, currAllowedContentTypes, currDefaultTemplate);
|
||||
mappedContentTypes.Add(contentType);
|
||||
|
||||
//map the allowed content types
|
||||
//map the child content type ids
|
||||
MapCommonContentTypeObjects(contentType, currentCtId, result, parentContentTypeIds);
|
||||
|
||||
mappedContentTypes.Add(contentType);
|
||||
//Here we need to reset the current variables, we're now collecting data for a different content type
|
||||
currDefaultTemplate = -1;
|
||||
currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
}
|
||||
}
|
||||
|
||||
return mappedContentTypes;
|
||||
}
|
||||
|
||||
private static void MapCommonContentTypeObjects<T, TId>(T contentType, TId currentCtId, List<dynamic> result, IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
|
||||
where T : IContentTypeBase
|
||||
where TId : struct
|
||||
private static IContentType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes, int currDefaultTemplate)
|
||||
{
|
||||
//map the allowed content types
|
||||
contentType.AllowedContentTypes = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
//use tuple so we can use distinct on all vals
|
||||
.Select(x => new Tuple<int?, int?, string>(x.ctaAllowedId, x.ctaSortOrder, x.ctaAlias))
|
||||
.Where(x => x.Item1.HasValue && x.Item2.HasValue && x.Item3 != null)
|
||||
.Distinct()
|
||||
.Select(x => new ContentTypeSort(new Lazy<int>(() => x.Item1.Value), x.Item2.Value, x.Item3))
|
||||
.ToList();
|
||||
// * set the default template to the first one if a default isn't found
|
||||
// * create the DTO object
|
||||
// * create the content type object
|
||||
// * map the allowed content types
|
||||
// * add to the outgoing list
|
||||
|
||||
//map the child content type ids
|
||||
parentContentTypeIds.Add(currentCtId, result
|
||||
.Where(x =>
|
||||
var dtDto = new ContentTypeTemplateDto
|
||||
{
|
||||
//create the content type dto
|
||||
ContentTypeDto = new ContentTypeDto
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? (TId?)x.chtParentId
|
||||
: (TId?)x.chtParentKey;
|
||||
})
|
||||
.Where(x => x.HasValue)
|
||||
.Distinct()
|
||||
.Select(x => x.Value).ToList());
|
||||
Alias = currCt.ctAlias,
|
||||
AllowAtRoot = currCt.ctAllowAtRoot,
|
||||
Description = currCt.ctDesc,
|
||||
Icon = currCt.ctIcon,
|
||||
IsContainer = currCt.ctIsContainer,
|
||||
NodeId = currCt.ctId,
|
||||
PrimaryKey = currCt.ctPk,
|
||||
Thumbnail = currCt.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = currCt.nCreateDate,
|
||||
Level = (short)currCt.nLevel,
|
||||
NodeId = currCt.ctId,
|
||||
NodeObjectType = currCt.nObjectType,
|
||||
ParentId = currCt.nParentId,
|
||||
Path = currCt.nPath,
|
||||
SortOrder = currCt.nSortOrder,
|
||||
Text = currCt.nName,
|
||||
Trashed = currCt.nTrashed,
|
||||
UniqueId = currCt.nUniqueId,
|
||||
UserId = currCt.nUser
|
||||
}
|
||||
},
|
||||
ContentTypeNodeId = currCt.ctId,
|
||||
IsDefault = currDefaultTemplate != -1,
|
||||
TemplateNodeId = currDefaultTemplate != -1 ? currDefaultTemplate : 0,
|
||||
};
|
||||
|
||||
//now create the content type object
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var contentType = factory.BuildContentTypeEntity(dtDto.ContentTypeDto);
|
||||
|
||||
// NOTE
|
||||
// that was done by the factory but makes little sense, moved here, so
|
||||
// now we have to reset dirty props again (as the factory does it) and yet,
|
||||
// we are not managing allowed templates... the whole thing is weird.
|
||||
((ContentType)contentType).DefaultTemplateId = dtDto.TemplateNodeId;
|
||||
contentType.ResetDirtyProperties(false);
|
||||
|
||||
//map the allowed content types
|
||||
contentType.AllowedContentTypes = currAllowedContentTypes;
|
||||
|
||||
return contentType;
|
||||
}
|
||||
|
||||
internal static void MapGroupsAndProperties(int[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
@@ -1109,14 +1050,14 @@ AND umbracoNode.id <> @id",
|
||||
// therefore the union of the two contains all of the property type and property group information we need
|
||||
// NOTE: MySQL requires a SELECT * FROM the inner union in order to be able to sort . lame.
|
||||
|
||||
var sqlBuilder = new StringBuilder(@"SELECT PG.contenttypeNodeId as contentTypeId,
|
||||
PT.ptUniqueId as ptUniqueID, PT.ptId, PT.ptAlias, PT.ptDesc,PT.ptMandatory,PT.ptName,PT.ptSortOrder,PT.ptRegExp,
|
||||
var sqlBuilder = new StringBuilder(@"SELECT PG.contenttypeNodeId as contentTypeId,
|
||||
PT.ptUniqueId as ptUniqueID, PT.ptId, PT.ptAlias, PT.ptDesc,PT.ptMandatory,PT.ptName,PT.ptSortOrder,PT.ptRegExp,
|
||||
PT.dtId,PT.dtDbType,PT.dtPropEdAlias,
|
||||
PG.id as pgId, PG.uniqueID as pgKey, PG.sortorder as pgSortOrder, PG." + sqlSyntax.GetQuotedColumnName("text") + @" as pgText
|
||||
FROM cmsPropertyTypeGroup as PG
|
||||
LEFT JOIN
|
||||
(
|
||||
SELECT PT.uniqueID as ptUniqueId, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
SELECT PT.uniqueID as ptUniqueId, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.mandatory as ptMandatory, PT.Name as ptName, PT.sortOrder as ptSortOrder, PT.validationRegExp as ptRegExp,
|
||||
PT.propertyTypeGroupId as ptGroupId,
|
||||
DT.dbType as dtDbType, DT.nodeId as dtId, DT.propertyEditorAlias as dtPropEdAlias
|
||||
@@ -1126,11 +1067,11 @@ AND umbracoNode.id <> @id",
|
||||
) as PT
|
||||
ON PT.ptGroupId = PG.id
|
||||
WHERE (PG.contenttypeNodeId in (@contentTypeIds))
|
||||
|
||||
|
||||
UNION
|
||||
|
||||
SELECT PT.contentTypeId as contentTypeId,
|
||||
PT.uniqueID as ptUniqueID, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.uniqueID as ptUniqueID, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.mandatory as ptMandatory, PT.Name as ptName, PT.sortOrder as ptSortOrder, PT.validationRegExp as ptRegExp,
|
||||
DT.nodeId as dtId, DT.dbType as dtDbType, DT.propertyEditorAlias as dtPropEdAlias,
|
||||
PG.id as pgId, PG.uniqueID as pgKey, PG.sortorder as pgSortOrder, PG." + sqlSyntax.GetQuotedColumnName("text") + @" as pgText
|
||||
@@ -1271,5 +1212,19 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
return PerformExists(id);
|
||||
}
|
||||
|
||||
public string GetUniqueAlias(string alias)
|
||||
{
|
||||
// alias is unique accross ALL content types!
|
||||
var aliasColumn = SqlSyntax.GetQuotedColumnName("alias");
|
||||
var aliases = Database.Fetch<string>(@"SELECT cmsContentType." + aliasColumn + @" FROM cmsContentType
|
||||
INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id
|
||||
WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
|
||||
new { pattern = alias + "%", objectType = NodeObjectTypeId });
|
||||
var i = 1;
|
||||
string test;
|
||||
while (aliases.Contains(test = alias + i)) i++;
|
||||
return test;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires:true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,27 +54,29 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
return ContentTypeQueryMapper.GetContentTypes(ids, Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
//NOTE: This logic should never be executed according to our cache policy
|
||||
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository)
|
||||
.Where(x => ids.Contains(x.Id));
|
||||
}
|
||||
|
||||
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetByQuery(IQuery<IContentType> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContentType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeTemplateDto, ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>();
|
||||
|
||||
return
|
||||
//This returns a lookup from the GetAll cached looup
|
||||
(dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>())
|
||||
//order the result by name
|
||||
.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,6 +187,22 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
PersistDeletedItem((IEntity)child);
|
||||
}
|
||||
|
||||
//Before we call the base class methods to run all delete clauses, we need to first
|
||||
// delete all of the property data associated with this document type. Normally this will
|
||||
// be done in the ContentTypeService by deleting all associated content first, but in some cases
|
||||
// like when we switch a document type, there is property data left over that is linked
|
||||
// to the previous document type. So we need to ensure it's removed.
|
||||
var sql = new Sql().Select("DISTINCT cmsPropertyData.propertytypeid")
|
||||
.From<PropertyDataDto>(SqlSyntax)
|
||||
.InnerJoin<PropertyTypeDto>(SqlSyntax)
|
||||
.On<PropertyDataDto, PropertyTypeDto>(SqlSyntax, dto => dto.PropertyTypeId, dto => dto.Id)
|
||||
.InnerJoin<ContentTypeDto>(SqlSyntax)
|
||||
.On<ContentTypeDto, PropertyTypeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.ContentTypeId)
|
||||
.Where<ContentTypeDto>(dto => dto.NodeId == entity.Id);
|
||||
|
||||
//Delete all cmsPropertyData where propertytypeid EXISTS in the subquery above
|
||||
Database.Execute(SqlSyntax.GetDeleteSubquery("cmsPropertyData", "propertytypeid", sql));
|
||||
|
||||
base.PersistDeletedItem(entity);
|
||||
}
|
||||
|
||||
@@ -284,9 +305,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
//var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
//var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
//return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override void PersistDeletedItem(EntityContainer entity)
|
||||
{
|
||||
EnsureContainerType(entity);
|
||||
|
||||
var nodeDto = Database.FirstOrDefault<NodeDto>(new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.NodeId == entity.Id && dto.NodeObjectType == entity.ContainerObjectType));
|
||||
@@ -160,6 +162,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override void PersistNewItem(EntityContainer entity)
|
||||
{
|
||||
EnsureContainerType(entity);
|
||||
|
||||
entity.Name = entity.Name.Trim();
|
||||
Mandate.ParameterNotNullOrEmpty(entity.Name, "entity.Name");
|
||||
|
||||
@@ -219,6 +223,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//
|
||||
protected override void PersistUpdatedItem(EntityContainer entity)
|
||||
{
|
||||
EnsureContainerType(entity);
|
||||
|
||||
entity.Name = entity.Name.Trim();
|
||||
Mandate.ParameterNotNullOrEmpty(entity.Name, "entity.Name");
|
||||
|
||||
@@ -268,5 +274,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
entity.SortOrder = 0;
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
private void EnsureContainerType(EntityContainer entity)
|
||||
{
|
||||
if (entity.ContainerObjectType != NodeObjectTypeId)
|
||||
{
|
||||
throw new InvalidOperationException("The container type does not match the repository object type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,5 +32,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Derives a unique alias from an existing alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The original alias.</param>
|
||||
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
|
||||
/// /// <remarks>Unique accross all content, media and member types.</remarks>
|
||||
string GetUniqueAlias(string alias);
|
||||
}
|
||||
}
|
||||
@@ -15,5 +15,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
|
||||
|
||||
IEnumerable<MoveEventInfo<IMediaType>> Move(IMediaType toMove, EntityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// Derives a unique alias from an existing alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The original alias.</param>
|
||||
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
|
||||
/// <remarks>Unique accross all content, media and member types.</remarks>
|
||||
string GetUniqueAlias(string alias);
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,44 +34,46 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires: true));
|
||||
}
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(int id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
|
||||
new[] { id }, Database, SqlSyntax, this);
|
||||
|
||||
var contentType = contentTypes.SingleOrDefault();
|
||||
return contentType;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetAll(params int[] ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
return ContentTypeQueryMapper.GetMediaTypes(ids, Database, SqlSyntax, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
|
||||
//NOTE: This logic should never be executed according to our cache policy
|
||||
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this)
|
||||
.Where(x => ids.Contains(x.Id));
|
||||
}
|
||||
|
||||
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetByQuery(IQuery<IMediaType> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IMediaType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>();
|
||||
|
||||
return
|
||||
//This returns a lookup from the GetAll cached looup
|
||||
(dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>())
|
||||
//order the result by name
|
||||
.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,9 +180,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
//var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
//var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
//return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,29 +33,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires: true));
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of RepositoryBase<int, IMemberType>
|
||||
|
||||
|
||||
protected override IMemberType PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
new PropertyTypePropertyGroupRelator().Map, sql);
|
||||
|
||||
if (dtos == null || dtos.Any() == false)
|
||||
return null;
|
||||
|
||||
var factory = new MemberTypeReadOnlyFactory();
|
||||
var member = factory.BuildEntity(dtos.First());
|
||||
|
||||
return member;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
|
||||
@@ -63,10 +51,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
if (ids.Any())
|
||||
{
|
||||
//NOTE: This logic should never be executed according to our cache policy
|
||||
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
|
||||
sql.Where(statement);
|
||||
}
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId);
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
@@ -82,7 +71,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var subquery = translator.Translate();
|
||||
var sql = GetBaseQuery(false)
|
||||
.Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments))
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
@@ -90,11 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return BuildFromDtos(dtos);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<int, IMemberType>
|
||||
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
@@ -168,11 +153,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.MemberType); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit of Work Implementation
|
||||
|
||||
|
||||
protected override void PersistNewItem(IMemberType entity)
|
||||
{
|
||||
ValidateAlias(entity);
|
||||
@@ -243,8 +224,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Override so we can specify explicit db type's on any property types that are built-in.
|
||||
@@ -282,9 +261,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
//var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
//var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
//return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual TId GetEntityId(TEntity entity)
|
||||
{
|
||||
return (TId)(object)entity.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The runtime cache used for this repo by default is the isolated cache for this type
|
||||
@@ -179,7 +183,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
using (var p = CachePolicyFactory.CreatePolicy())
|
||||
{
|
||||
return p.GetAll(ids, PerformGetAll);
|
||||
var result = p.GetAll(ids, PerformGetAll);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +493,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (aliases.Any() == false) return base.GetAll();
|
||||
|
||||
//return from base.GetAll, this is all cached
|
||||
return base.GetAll().Where(x => aliases.Contains(x.Alias));
|
||||
return base.GetAll().Where(x => aliases.InvariantContains(x.Alias));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetChildren(int masterTemplateId)
|
||||
@@ -505,7 +506,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var parent = all.FirstOrDefault(x => x.Id == masterTemplateId);
|
||||
if (parent == null) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var children = all.Where(x => x.MasterTemplateAlias == parent.Alias);
|
||||
var children = all.Where(x => x.MasterTemplateAlias.InvariantEquals(parent.Alias));
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -514,7 +515,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//return from base.GetAll, this is all cached
|
||||
return base.GetAll().Where(x => alias.IsNullOrWhiteSpace()
|
||||
? x.MasterTemplateAlias.IsNullOrWhiteSpace()
|
||||
: x.MasterTemplateAlias == alias);
|
||||
: x.MasterTemplateAlias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetDescendants(int masterTemplateId)
|
||||
@@ -549,7 +550,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var descendants = new List<ITemplate>();
|
||||
if (alias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var parent = all.FirstOrDefault(x => x.Alias == alias);
|
||||
var parent = all.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
if (parent == null) return Enumerable.Empty<ITemplate>();
|
||||
//recursively add all children
|
||||
AddChildren(all, descendants, parent.Alias);
|
||||
@@ -569,7 +570,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private void AddChildren(ITemplate[] all, List<ITemplate> descendants, string masterAlias)
|
||||
{
|
||||
var c = all.Where(x => x.MasterTemplateAlias == masterAlias).ToArray();
|
||||
var c = all.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray();
|
||||
descendants.AddRange(c);
|
||||
if (c.Any() == false) return;
|
||||
//recurse through all children
|
||||
@@ -590,7 +591,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//first get all template objects
|
||||
var allTemplates = base.GetAll().ToArray();
|
||||
|
||||
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias == alias);
|
||||
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
if (selfTemplate == null)
|
||||
{
|
||||
return null;
|
||||
@@ -599,11 +600,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var top = selfTemplate;
|
||||
while (top.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
top = allTemplates.Single(x => x.Alias == top.MasterTemplateAlias);
|
||||
top = allTemplates.Single(x => x.Alias.InvariantEquals(top.MasterTemplateAlias));
|
||||
}
|
||||
|
||||
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.Id));
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias == top.Alias);
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(top.Alias));
|
||||
//This now creates the hierarchy recursively
|
||||
topNode.Children = CreateChildren(topNode, childTemplates, allTemplates);
|
||||
|
||||
@@ -615,7 +616,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private static TemplateNode WalkTree(TemplateNode current, string alias)
|
||||
{
|
||||
//now walk the tree to find the node
|
||||
if (current.Template.Alias == alias)
|
||||
if (current.Template.Alias.InvariantEquals(alias))
|
||||
{
|
||||
return current;
|
||||
}
|
||||
@@ -747,7 +748,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//get this node's children
|
||||
var local = childTemplate;
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias == local.Alias);
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(local.Alias));
|
||||
|
||||
//recurse
|
||||
child.Children = CreateChildren(child, kids, allTemplates);
|
||||
@@ -777,7 +778,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private bool AliasAlreadExists(ITemplate template)
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias == template.Alias && x.NodeId != template.Id);
|
||||
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias.InvariantEquals(template.Alias) && x.NodeId != template.Id);
|
||||
var count = Database.ExecuteScalar<int>(sql);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
GuidColumnDefinition = "char(36)";
|
||||
|
||||
DefaultValueFormat = "DEFAULT {0}";
|
||||
|
||||
InitColumnTypeMap();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Umbraco.Core.Persistence
|
||||
/// Represents the Umbraco implementation of the PetaPoco Database object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this object exists for 'future proofing' our implementation. By having our own inheritied implementation we
|
||||
/// Currently this object exists for 'future proofing' our implementation. By having our own inheritied implementation we
|
||||
/// can then override any additional execution (such as additional loggging, functionality, etc...) that we need to without breaking compatibility since we'll always be exposing
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// </remarks>
|
||||
public class UmbracoDatabase : Database, IDisposeOnRequestEnd
|
||||
{
|
||||
@@ -111,7 +111,9 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
public override IDbConnection OnConnectionOpened(IDbConnection connection)
|
||||
{
|
||||
// wrap the connection with a profiling connection that tracks timings
|
||||
// propagate timeout if none yet
|
||||
|
||||
// wrap the connection with a profiling connection that tracks timings
|
||||
return new StackExchange.Profiling.Data.ProfiledDbConnection(connection as DbConnection, MiniProfiler.Current);
|
||||
}
|
||||
|
||||
@@ -121,6 +123,14 @@ namespace Umbraco.Core.Persistence
|
||||
base.OnException(x);
|
||||
}
|
||||
|
||||
public override void OnExecutingCommand(IDbCommand cmd)
|
||||
{
|
||||
// if no timeout is specified, and the connection has a longer timeout, use it
|
||||
if (OneTimeCommandTimeout == 0 && CommandTimeout == 0 && cmd.Connection.ConnectionTimeout > 30)
|
||||
cmd.CommandTimeout = cmd.Connection.ConnectionTimeout;
|
||||
base.OnExecutingCommand(cmd);
|
||||
}
|
||||
|
||||
public override void OnExecutedCommand(IDbCommand cmd)
|
||||
{
|
||||
if (EnableSqlTrace)
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using StackExchange.Profiling;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows us to profile items during app startup - before an HttpRequest is created
|
||||
/// </summary>
|
||||
internal class StartupWebProfilerProvider : WebRequestProfilerProvider
|
||||
{
|
||||
public StartupWebProfilerProvider()
|
||||
{
|
||||
_startupPhase = StartupPhase.Boot;
|
||||
//create the startup profiler
|
||||
_startupProfiler = new MiniProfiler("http://localhost/umbraco-startup", ProfileLevel.Verbose)
|
||||
{
|
||||
Name = "StartupProfiler"
|
||||
};
|
||||
}
|
||||
|
||||
private MiniProfiler _startupProfiler;
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
|
||||
|
||||
private enum StartupPhase
|
||||
{
|
||||
None = 0,
|
||||
Boot = 1,
|
||||
Request = 2
|
||||
}
|
||||
|
||||
private volatile StartupPhase _startupPhase;
|
||||
|
||||
public void BootComplete()
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase != StartupPhase.Boot) return;
|
||||
}
|
||||
|
||||
using (var l = new UpgradeableReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase == StartupPhase.Boot)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
|
||||
////Now we need to transfer some information from our startup phase to the normal
|
||||
////web request phase to output the startup profiled information.
|
||||
////Stop our internal startup profiler, this will write out it's results to storage.
|
||||
//StopProfiler(_startupProfiler);
|
||||
//SaveProfiler(_startupProfiler);
|
||||
|
||||
_startupPhase = StartupPhase.Request;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop(bool discardResults)
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase == StartupPhase.None)
|
||||
{
|
||||
base.Stop(discardResults);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
using (var l = new UpgradeableReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase > 0 && base.GetCurrentProfiler() == null)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
|
||||
_startupPhase = StartupPhase.None;
|
||||
|
||||
if (HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Items[":mini-profiler:"] = _startupProfiler;
|
||||
base.Stop(discardResults);
|
||||
_startupProfiler = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Stop(discardResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override MiniProfiler Start(ProfileLevel level)
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase > 0 && base.GetCurrentProfiler() == null)
|
||||
{
|
||||
SetProfilerActive(_startupProfiler);
|
||||
return _startupProfiler;
|
||||
}
|
||||
|
||||
return base.Start(level);
|
||||
}
|
||||
}
|
||||
|
||||
public override MiniProfiler GetCurrentProfiler()
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var current = base.GetCurrentProfiler();
|
||||
if (current == null) return _startupProfiler;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return _startupProfiler;
|
||||
}
|
||||
}
|
||||
|
||||
return base.GetCurrentProfiler();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,24 +12,15 @@ namespace Umbraco.Core.Profiling
|
||||
/// </summary>
|
||||
internal class WebProfiler : IProfiler
|
||||
{
|
||||
private StartupWebProfilerProvider _startupWebProfilerProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Binds to application events to enable the MiniProfiler
|
||||
/// </remarks>
|
||||
internal WebProfiler()
|
||||
{
|
||||
//setup some defaults
|
||||
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
|
||||
MiniProfiler.Settings.StackMaxLength = 5000;
|
||||
|
||||
//At this point we know that we've been constructed during app startup, there won't be an HttpRequest in the HttpContext
|
||||
// since it hasn't started yet. So we need to do some hacking to enable profiling during startup.
|
||||
_startupWebProfilerProvider = new StartupWebProfilerProvider();
|
||||
//this should always be the case during startup, we'll need to set a custom profiler provider
|
||||
MiniProfiler.Settings.ProfilerProvider = _startupWebProfilerProvider;
|
||||
|
||||
//Binds to application events to enable the MiniProfiler with a real HttpRequest
|
||||
UmbracoApplicationBase.ApplicationInit += UmbracoApplicationApplicationInit;
|
||||
}
|
||||
|
||||
@@ -62,12 +53,7 @@ namespace Umbraco.Core.Profiling
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationEndRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (_startupWebProfilerProvider != null)
|
||||
{
|
||||
Stop();
|
||||
_startupWebProfilerProvider = null;
|
||||
}
|
||||
else if (CanPerformProfilingAction(sender))
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
@@ -80,11 +66,6 @@ namespace Umbraco.Core.Profiling
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationBeginRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (_startupWebProfilerProvider != null)
|
||||
{
|
||||
_startupWebProfilerProvider.BootComplete();
|
||||
}
|
||||
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Start();
|
||||
@@ -143,7 +124,9 @@ namespace Umbraco.Core.Profiling
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
{
|
||||
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
|
||||
MiniProfiler.Settings.StackMaxLength = 5000;
|
||||
MiniProfiler.Start();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <summary>
|
||||
/// Manages the list of IPropertyEditorValueConverter's
|
||||
/// </summary>
|
||||
[Obsolete("IPropertyEditorValueConverter is obsolete, but we need to support them until v8, to resolve the correct converter types use: PropertyValueConvertersResolver")]
|
||||
internal sealed class PropertyEditorValueConvertersResolver : ManyObjectsResolverBase<PropertyEditorValueConvertersResolver, IPropertyEditorValueConverter>
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -12,6 +12,9 @@ using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// This ensures that the grid config is merged in with the front-end value
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
|
||||
[PropertyValueType(typeof(JToken))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
@@ -90,7 +93,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<JsonValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
|
||||
LogHelper.Error<GridValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// This ensures that the cropper config (pre-values/crops) are merged in with the front-end value.
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter(typeof (JsonValueConverter))] //this shadows the JsonValueConverter
|
||||
[PropertyValueType(typeof (JToken))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
public class ImageCropperValueConverter : JsonValueConverter
|
||||
{
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
|
||||
public ImageCropperValueConverter()
|
||||
{
|
||||
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
|
||||
}
|
||||
|
||||
public ImageCropperValueConverter(IDataTypeService dataTypeService)
|
||||
{
|
||||
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
|
||||
_dataTypeService = dataTypeService;
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ImageCropperAlias);
|
||||
}
|
||||
|
||||
internal static void MergePreValues(JObject currentValue, IDataTypeService dataTypeService, int dataTypeId)
|
||||
{
|
||||
//need to lookup the pre-values for this data type
|
||||
//TODO: Change all singleton access to use ctor injection in v8!!!
|
||||
var dt = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId);
|
||||
|
||||
if (dt != null && dt.IsDictionaryBased && dt.PreValuesAsDictionary.ContainsKey("crops"))
|
||||
{
|
||||
var cropsString = dt.PreValuesAsDictionary["crops"].Value;
|
||||
JArray preValueCrops;
|
||||
try
|
||||
{
|
||||
preValueCrops = JsonConvert.DeserializeObject<JArray>(cropsString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ImageCropperValueConverter>("Could not parse the string " + cropsString + " to a json object", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
//now we need to merge the crop values - the alias + width + height comes from pre-configured pre-values,
|
||||
// however, each crop can store it's own coordinates
|
||||
|
||||
JArray existingCropsArray;
|
||||
if (currentValue["crops"] != null)
|
||||
{
|
||||
existingCropsArray = (JArray)currentValue["crops"];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentValue["crops"] = existingCropsArray = new JArray();
|
||||
}
|
||||
|
||||
foreach (var preValueCrop in preValueCrops.Where(x => x.HasValues))
|
||||
{
|
||||
var found = existingCropsArray.FirstOrDefault(x =>
|
||||
{
|
||||
if (x.HasValues && x["alias"] != null)
|
||||
{
|
||||
return x["alias"].Value<string>() == preValueCrop["alias"].Value<string>();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (found != null)
|
||||
{
|
||||
found["width"] = preValueCrop["width"];
|
||||
found["height"] = preValueCrop["height"];
|
||||
}
|
||||
else
|
||||
{
|
||||
existingCropsArray.Add(preValueCrop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
var sourceString = source.ToString();
|
||||
|
||||
if (sourceString.DetectIsJson())
|
||||
{
|
||||
JObject obj;
|
||||
try
|
||||
{
|
||||
obj = JsonConvert.DeserializeObject<JObject>(sourceString, new JsonSerializerSettings
|
||||
{
|
||||
Culture = CultureInfo.InvariantCulture,
|
||||
FloatParseHandling = FloatParseHandling.Decimal
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ImageCropperValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
|
||||
return sourceString;
|
||||
}
|
||||
|
||||
MergePreValues(obj, _dataTypeService, propertyType.DataTypeId);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
//it's not json, just return the string
|
||||
return sourceString;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// We need this property converter so that we always force the value of a label to be a string
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Without a property converter defined for the label type, the value will be converted with
|
||||
/// the `ConvertUsingDarkMagic` method which will try to parse the value into it's correct type, but this
|
||||
/// can cause issues if the string is detected as a number and then strips leading zeros.
|
||||
/// Example: http://issues.umbraco.org/issue/U4-7929
|
||||
/// </remarks>
|
||||
[DefaultPropertyValueConverter]
|
||||
[PropertyValueType(typeof (string))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
public class LabelValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias);
|
||||
}
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
return source == null ? string.Empty : source.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,10 +103,18 @@ namespace Umbraco.Core.Security
|
||||
var backOfficeIdentity = http.User.Identity as UmbracoBackOfficeIdentity;
|
||||
if (backOfficeIdentity != null) return backOfficeIdentity;
|
||||
|
||||
//Check if there's more than one identity assigned and see if it's a UmbracoBackOfficeIdentity and use that
|
||||
var claimsPrincipal = http.User as ClaimsPrincipal;
|
||||
if (claimsPrincipal != null)
|
||||
{
|
||||
backOfficeIdentity = claimsPrincipal.Identities.OfType<UmbracoBackOfficeIdentity>().FirstOrDefault();
|
||||
if (backOfficeIdentity != null) return backOfficeIdentity;
|
||||
}
|
||||
|
||||
//Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session
|
||||
var claimsIdentity = http.User.Identity as ClaimsIdentity;
|
||||
if (claimsIdentity != null && claimsIdentity.IsAuthenticated)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity);
|
||||
@@ -167,74 +175,18 @@ namespace Umbraco.Core.Security
|
||||
/// This clears the forms authentication cookie for webapi since cookies are handled differently
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead")]
|
||||
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead", true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void UmbracoLogoutWebApi(this HttpResponseMessage response)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException("response");
|
||||
//remove the cookie
|
||||
var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
//remove the preview cookie too
|
||||
var prevCookie = new CookieHeaderValue(Constants.Web.PreviewCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
//remove the external login cookie too
|
||||
var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
|
||||
response.Headers.AddCookies(new[] { authCookie, prevCookie, extLoginCookie });
|
||||
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
||||
}
|
||||
|
||||
[Obsolete("Use WebSecurity.SetPrincipalForRequest")]
|
||||
[Obsolete("Use WebSecurity.SetPrincipalForRequest", true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static FormsAuthenticationTicket UmbracoLoginWebApi(this HttpResponseMessage response, IUser user)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException("response");
|
||||
|
||||
//remove the external login cookie
|
||||
var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
|
||||
var userDataString = JsonConvert.SerializeObject(Mapper.Map<UserData>(user));
|
||||
|
||||
var ticket = new FormsAuthenticationTicket(
|
||||
4,
|
||||
user.Username,
|
||||
DateTime.Now,
|
||||
DateTime.Now.AddMinutes(GlobalSettings.TimeOutInMinutes),
|
||||
true,
|
||||
userDataString,
|
||||
"/"
|
||||
);
|
||||
|
||||
// Encrypt the cookie using the machine key for secure transport
|
||||
var encrypted = FormsAuthentication.Encrypt(ticket);
|
||||
|
||||
//add the cookie
|
||||
var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, encrypted)
|
||||
{
|
||||
//Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way
|
||||
Expires = DateTime.Now.AddMinutes(1440),
|
||||
Path = "/",
|
||||
Secure = GlobalSettings.UseSSL,
|
||||
HttpOnly = true
|
||||
};
|
||||
|
||||
response.Headers.AddCookies(new[] { authCookie, extLoginCookie });
|
||||
|
||||
return ticket;
|
||||
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
public class BackOfficeClaimsIdentityFactory : ClaimsIdentityFactory<BackOfficeIdentityUser, int>
|
||||
{
|
||||
public BackOfficeClaimsIdentityFactory()
|
||||
{
|
||||
SecurityStampClaimType = Constants.Security.SessionIdClaimType;
|
||||
UserNameClaimType = ClaimTypes.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a ClaimsIdentity from a user
|
||||
/// </summary>
|
||||
@@ -20,7 +26,7 @@ namespace Umbraco.Core.Security
|
||||
|
||||
var umbracoIdentity = new UmbracoBackOfficeIdentity(baseIdentity,
|
||||
//set a new session id
|
||||
new UserData(Guid.NewGuid().ToString("N"))
|
||||
new UserData
|
||||
{
|
||||
Id = user.Id,
|
||||
Username = user.UserName,
|
||||
@@ -29,7 +35,8 @@ namespace Umbraco.Core.Security
|
||||
Culture = user.Culture,
|
||||
Roles = user.Roles.Select(x => x.RoleId).ToArray(),
|
||||
StartContentNode = user.StartContentId,
|
||||
StartMediaNode = user.StartMediaId
|
||||
StartMediaNode = user.StartMediaId,
|
||||
SessionId = user.SecurityStamp
|
||||
});
|
||||
|
||||
return umbracoIdentity;
|
||||
|
||||
@@ -759,12 +759,13 @@ namespace Umbraco.Core.Security
|
||||
|
||||
//This is the correct way to implement this (as per the sql membership provider)
|
||||
|
||||
switch ((int)PasswordFormat)
|
||||
switch (PasswordFormat)
|
||||
{
|
||||
case 0:
|
||||
case MembershipPasswordFormat.Clear:
|
||||
return pass;
|
||||
case 1:
|
||||
case MembershipPasswordFormat.Hashed:
|
||||
throw new ProviderException("Provider can not decrypt hashed password");
|
||||
case MembershipPasswordFormat.Encrypted:
|
||||
default:
|
||||
var bytes = DecryptPassword(Convert.FromBase64String(pass));
|
||||
return bytes == null ? null : Encoding.Unicode.GetString(bytes, 16, bytes.Length - 16);
|
||||
|
||||
@@ -209,17 +209,19 @@ namespace Umbraco.Core.Security
|
||||
|
||||
if (HasClaim(x => x.Type == ClaimTypes.Locality) == false)
|
||||
AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
|
||||
////TODO: Not sure why this is null sometimes, it shouldn't be. Somewhere it's not being set
|
||||
/// I think it's due to some bug I had in chrome, we'll see
|
||||
//if (UserData.SessionId.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// UserData.SessionId = Guid.NewGuid().ToString();
|
||||
//}
|
||||
|
||||
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false)
|
||||
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
|
||||
//The security stamp claim is also required... this is because this claim type is hard coded
|
||||
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
|
||||
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
|
||||
{
|
||||
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
}
|
||||
}
|
||||
|
||||
//Add each app as a separate claim
|
||||
if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Security
|
||||
/// Use this constructor to create/assign new UserData to the ticket
|
||||
/// </summary>
|
||||
/// <param name="sessionId">
|
||||
/// A unique id that is assigned to this ticket
|
||||
/// The security stamp for the user
|
||||
/// </param>
|
||||
public UserData(string sessionId)
|
||||
{
|
||||
@@ -30,8 +30,7 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used to Id the current ticket which we can then use to mitigate csrf attacks
|
||||
/// and other things that require request validation.
|
||||
/// This is the 'security stamp' for validation
|
||||
/// </summary>
|
||||
[DataMember(Name = "sessionId")]
|
||||
public string SessionId { get; set; }
|
||||
@@ -42,8 +41,6 @@ namespace Umbraco.Core.Security
|
||||
[DataMember(Name = "roles")]
|
||||
public string[] Roles { get; set; }
|
||||
|
||||
//public int SessionTimeout { get; set; }
|
||||
|
||||
[DataMember(Name = "username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// This is required if we want to force JSON.Net to not use .Net TypeConverters during serialization/deserialization
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// In some cases thsi is required if your model has an explicit type converter, see: http://stackoverflow.com/a/31328131/694494
|
||||
///
|
||||
/// NOTE: I was going to use this for the ImageCropDataSetConverter to convert to String, which would have worked by putting this attribute:
|
||||
/// [JsonConverter(typeof(NoTypeConverterJsonConverter{ImageCropDataSet}))] on top of the ImageCropDataSet class, however it turns out we
|
||||
/// don't require this because to convert to string, we just override ToString().
|
||||
/// I'll leave this class here for the future though.
|
||||
/// </remarks>
|
||||
internal class NoTypeConverterJsonConverter<T> : JsonConverter
|
||||
{
|
||||
static readonly IContractResolver resolver = new NoTypeConverterContractResolver();
|
||||
|
||||
private class NoTypeConverterContractResolver : DefaultContractResolver
|
||||
{
|
||||
protected override JsonContract CreateContract(Type objectType)
|
||||
{
|
||||
if (typeof(T).IsAssignableFrom(objectType))
|
||||
{
|
||||
var contract = this.CreateObjectContract(objectType);
|
||||
contract.Converter = null; // Also null out the converter to prevent infinite recursion.
|
||||
return contract;
|
||||
}
|
||||
return base.CreateContract(objectType);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(T).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
return JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Deserialize(reader, objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Serialize(writer, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -910,7 +910,7 @@ namespace Umbraco.Core.Services
|
||||
new MoveEventArgs<IContent>(evtMsgs, new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContent>>
|
||||
@@ -957,7 +957,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1080,7 +1080,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IContent>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
using (new WriteLock(Locker))
|
||||
@@ -1124,7 +1124,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1147,7 +1147,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<IContent>(content, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
//Make sure that published content is unpublished before being deleted
|
||||
@@ -1178,7 +1178,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,6 +1227,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user issueing the delete operation</param>
|
||||
public void DeleteContentOfType(int contentTypeId, int userId = 0)
|
||||
{
|
||||
//TODO: This currently this is called from the ContentTypeService but that needs to change,
|
||||
// if we are deleting a content type, we should just delete the data and do this operation slightly differently.
|
||||
// This method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
@@ -2043,7 +2050,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IContent>(content, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2075,7 +2082,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Save Content performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Services
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IMediaService _mediaService;
|
||||
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
@@ -44,8 +44,9 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Containers
|
||||
|
||||
public Attempt<int> CreateContentTypeContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContentTypeContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
@@ -57,20 +58,32 @@ namespace Umbraco.Core.Services
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingContentTypeContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
|
||||
SavedContentTypeContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<int> CreateMediaTypeContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateMediaTypeContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
{
|
||||
@@ -82,42 +95,83 @@ namespace Umbraco.Core.Services
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingMediaTypeContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
|
||||
SavedMediaTypeContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveContentTypeContainer(EntityContainer container, int userId = 0)
|
||||
public Attempt<OperationStatus> SaveContentTypeContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
SaveContainer(container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type", userId);
|
||||
return SaveContainer(
|
||||
SavingContentTypeContainer, SavedContentTypeContainer,
|
||||
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type", userId);
|
||||
}
|
||||
|
||||
public void SaveMediaTypeContainer(EntityContainer container, int userId = 0)
|
||||
public Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
SaveContainer(container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type", userId);
|
||||
return SaveContainer(
|
||||
SavingMediaTypeContainer, SavedMediaTypeContainer,
|
||||
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type", userId);
|
||||
}
|
||||
|
||||
private void SaveContainer(EntityContainer container, Guid containerObjectType, string objectTypeName, int userId)
|
||||
private Attempt<OperationStatus> SaveContainer(
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savingEvent,
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
|
||||
EntityContainer container,
|
||||
Guid containerObjectType,
|
||||
string objectTypeName, int userId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (container.ContainedObjectType != containerObjectType)
|
||||
throw new InvalidOperationException("Not a " + objectTypeName + " container.");
|
||||
{
|
||||
var ex = new InvalidOperationException("Not a " + objectTypeName + " container.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (container.HasIdentity && container.IsPropertyDirty("ParentId"))
|
||||
throw new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
{
|
||||
var ex = new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (savingEvent.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType))
|
||||
{
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
|
||||
savedEvent.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
public EntityContainer GetContentTypeContainer(int containerId)
|
||||
@@ -175,7 +229,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public EntityContainer GetContentTypeContainer(Guid containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeGuid);
|
||||
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeContainerGuid);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContentTypeContainers(int[] containerIds)
|
||||
@@ -199,14 +253,14 @@ namespace Umbraco.Core.Services
|
||||
.Where(x => x != int.MinValue && x != contentType.Id)
|
||||
.ToArray();
|
||||
|
||||
return GetContentTypeContainers(ancestorIds);
|
||||
return GetContentTypeContainers(ancestorIds);
|
||||
}
|
||||
|
||||
public EntityContainer GetMediaTypeContainer(Guid containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeGuid);
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeContainerGuid);
|
||||
}
|
||||
|
||||
|
||||
private EntityContainer GetContainer(Guid containerId, Guid containerObjectType)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -226,28 +280,54 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteContentTypeContainer(int containerId, int userId = 0)
|
||||
public Attempt<OperationStatus> DeleteContentTypeContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return;
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingContentTypeContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
DeletedContentTypeContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMediaTypeContainer(int containerId, int userId = 0)
|
||||
public Attempt<OperationStatus> DeleteMediaTypeContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return;
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingMediaTypeContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
DeletedMediaTypeContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
@@ -300,7 +380,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IContentType Copy(IContentType original, string alias, string name, int parentId = -1)
|
||||
{
|
||||
IContentType parent = null;
|
||||
IContentType parent = null;
|
||||
if (parentId > 0)
|
||||
{
|
||||
parent = GetContentType(parentId);
|
||||
@@ -334,7 +414,7 @@ namespace Umbraco.Core.Services
|
||||
Mandate.ParameterNotNullOrEmpty(alias, "alias");
|
||||
if (parent != null)
|
||||
{
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
|
||||
}
|
||||
|
||||
var clone = original.DeepCloneWithResetIdentities(alias);
|
||||
@@ -360,7 +440,7 @@ namespace Umbraco.Core.Services
|
||||
//set to root
|
||||
clone.ParentId = -1;
|
||||
}
|
||||
|
||||
|
||||
Save(clone);
|
||||
return clone;
|
||||
}
|
||||
@@ -425,7 +505,7 @@ namespace Umbraco.Core.Services
|
||||
public IEnumerable<IContentType> GetAllContentTypes(IEnumerable<Guid> ids)
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
{
|
||||
return repository.GetAll(ids.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -519,7 +599,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
//this should never occur, the content service should always be typed but we'll check anyways.
|
||||
_contentService.RePublishAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (firstType is IMediaType)
|
||||
{
|
||||
@@ -528,10 +608,10 @@ namespace Umbraco.Core.Services
|
||||
if (typedContentService != null)
|
||||
{
|
||||
typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int CountContentTypes()
|
||||
@@ -581,14 +661,17 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var contentType = compositionContentType as IContentType;
|
||||
var mediaType = compositionContentType as IMediaType;
|
||||
var memberType = compositionContentType as IMemberType; // should NOT do it here but... v8!
|
||||
|
||||
IContentTypeComposition[] allContentTypes;
|
||||
if (contentType != null)
|
||||
allContentTypes = GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
|
||||
else if (mediaType != null)
|
||||
allContentTypes = GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray();
|
||||
else if (memberType != null)
|
||||
return; // no compositions on members, always validate
|
||||
else
|
||||
throw new Exception("Composition is neither IContentType nor IMediaType?");
|
||||
throw new Exception("Composition is neither IContentType nor IMediaType nor IMemberType?");
|
||||
|
||||
var compositionAliases = compositionContentType.CompositionAliases();
|
||||
var compositions = allContentTypes.Where(x => compositionAliases.Any(y => x.Alias.Equals(y)));
|
||||
@@ -604,7 +687,7 @@ namespace Umbraco.Core.Services
|
||||
dependencies.Add(indirectReference);
|
||||
//Get all compositions for the current indirect reference
|
||||
var directReferences = indirectReference.ContentTypeComposition;
|
||||
|
||||
|
||||
foreach (var directReference in directReferences)
|
||||
{
|
||||
if (directReference.Id == compositionContentType.Id || directReference.Alias.Equals(compositionContentType.Alias)) continue;
|
||||
@@ -624,7 +707,7 @@ namespace Umbraco.Core.Services
|
||||
if (contentTypeDependency == null) continue;
|
||||
var intersect = contentTypeDependency.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).Intersect(propertyTypeAliases).ToArray();
|
||||
if (intersect.Length == 0) continue;
|
||||
|
||||
|
||||
throw new InvalidCompositionException(compositionContentType.Alias, intersect.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -636,7 +719,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user saving the ContentType</param>
|
||||
public void Save(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -666,7 +749,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = contentTypes.ToArray();
|
||||
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -702,12 +785,19 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user issueing the delete</param>
|
||||
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
|
||||
public void Delete(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
|
||||
{
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
|
||||
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
|
||||
// this method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
_contentService.DeleteContentOfType(contentType.Id);
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -735,7 +825,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = contentTypes.ToArray();
|
||||
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -761,7 +851,7 @@ namespace Umbraco.Core.Services
|
||||
Audit(AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMediaType"/> object by its Id
|
||||
/// </summary>
|
||||
@@ -894,7 +984,7 @@ namespace Umbraco.Core.Services
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
|
||||
if (MovingMediaType.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, containerId)),
|
||||
this))
|
||||
@@ -949,7 +1039,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContentType>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
@@ -977,6 +1067,92 @@ namespace Umbraco.Core.Services
|
||||
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
IMediaType copy;
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateMediaTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (containerId > 0)
|
||||
{
|
||||
var container = containerRepository.Get(containerId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
var alias = repository.GetUniqueAlias(toCopy.Alias);
|
||||
copy = toCopy.DeepCloneWithResetIdentities(alias);
|
||||
copy.Name = copy.Name + " (copy)"; // might not be unique
|
||||
|
||||
// if it has a parent, and the parent is a content type, unplug composition
|
||||
// all other compositions remain in place in the copied content type
|
||||
if (copy.ParentId > 0)
|
||||
{
|
||||
var parent = repository.Get(copy.ParentId);
|
||||
if (parent != null)
|
||||
copy.RemoveContentType(parent.Alias);
|
||||
}
|
||||
|
||||
copy.ParentId = containerId;
|
||||
repository.AddOrUpdate(copy);
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<IMediaType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<IMediaType, MoveOperationStatusType>(copy, MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
IContentType copy;
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (containerId > 0)
|
||||
{
|
||||
var container = containerRepository.Get(containerId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
var alias = repository.GetUniqueAlias(toCopy.Alias);
|
||||
copy = toCopy.DeepCloneWithResetIdentities(alias);
|
||||
copy.Name = copy.Name + " (copy)"; // might not be unique
|
||||
|
||||
// if it has a parent, and the parent is a content type, unplug composition
|
||||
// all other compositions remain in place in the copied content type
|
||||
if (copy.ParentId > 0)
|
||||
{
|
||||
var parent = repository.Get(copy.ParentId);
|
||||
if (parent != null)
|
||||
copy.RemoveContentType(parent.Alias);
|
||||
}
|
||||
|
||||
copy.ParentId = containerId;
|
||||
repository.AddOrUpdate(copy);
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<IContentType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<IContentType, MoveOperationStatusType>(copy, MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
@@ -984,7 +1160,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user saving the MediaType</param>
|
||||
public void Save(IMediaType mediaType, int userId = 0)
|
||||
{
|
||||
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
|
||||
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -996,7 +1172,7 @@ namespace Umbraco.Core.Services
|
||||
mediaType.CreatorId = userId;
|
||||
repository.AddOrUpdate(mediaType);
|
||||
uow.Commit();
|
||||
|
||||
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(mediaType);
|
||||
@@ -1035,7 +1211,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
//save it all in one go
|
||||
uow.Commit();
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
|
||||
@@ -1053,7 +1229,7 @@ namespace Umbraco.Core.Services
|
||||
/// <remarks>Deleting a <see cref="IMediaType"/> will delete all the <see cref="IMedia"/> objects based on this <see cref="IMediaType"/></remarks>
|
||||
public void Delete(IMediaType mediaType, int userId = 0)
|
||||
{
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
@@ -1083,7 +1259,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = mediaTypes.ToArray();
|
||||
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
|
||||
return;
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
@@ -1105,7 +1281,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, string.Format("Delete MediaTypes performed by user"), userId, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1172,19 +1348,29 @@ namespace Umbraco.Core.Services
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletingContentType;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavingContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavedContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletingContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletedContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavingMediaTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavedMediaTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletingMediaTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletedMediaTypeContainer;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletingContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
@@ -1194,7 +1380,7 @@ namespace Umbraco.Core.Services
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
|
||||
@@ -29,8 +29,9 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Containers
|
||||
|
||||
public Attempt<int> CreateContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
@@ -42,15 +43,26 @@ namespace Umbraco.Core.Services
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
|
||||
SavedContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,31 +119,65 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveContainer(EntityContainer container, int userId = 0)
|
||||
public Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)
|
||||
throw new InvalidOperationException("Not a data type container.");
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)
|
||||
{
|
||||
var ex = new InvalidOperationException("Not a " + Constants.ObjectTypes.DataTypeGuid + " container.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (container.HasIdentity && container.IsPropertyDirty("ParentId"))
|
||||
throw new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
{
|
||||
var ex = new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (SavingContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
|
||||
SavedContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
public void DeleteContainer(int containerId, int userId = 0)
|
||||
public Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return;
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
DeletedContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
@@ -537,6 +583,12 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
public static event TypedEventHandler<IDataTypeService, SaveEventArgs<EntityContainer>> SavingContainer;
|
||||
public static event TypedEventHandler<IDataTypeService, SaveEventArgs<EntityContainer>> SavedContainer;
|
||||
public static event TypedEventHandler<IDataTypeService, DeleteEventArgs<EntityContainer>> DeletingContainer;
|
||||
public static event TypedEventHandler<IDataTypeService, DeleteEventArgs<EntityContainer>> DeletedContainer;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<IDomain>(domain, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var args = new DeleteEventArgs<IDomain>(domain, false, evtMsgs);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
public IDomain GetByName(string name)
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IDomain>(domainEntity, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<IDomain>(domainEntity, false, evtMsgs), this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
@@ -268,11 +267,15 @@ namespace Umbraco.Core.Services
|
||||
structure.Add(new XElement("MediaType", allowedType.Alias));
|
||||
}
|
||||
|
||||
var genericProperties = new XElement("GenericProperties");
|
||||
var genericProperties = new XElement("GenericProperties"); // actually, all of them
|
||||
foreach (var propertyType in mediaType.PropertyTypes)
|
||||
{
|
||||
var definition = dataTypeService.GetDataTypeDefinitionById(propertyType.DataTypeDefinitionId);
|
||||
var propertyGroup = mediaType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
|
||||
var propertyGroup = propertyType.PropertyGroupId == null // true generic property
|
||||
? null
|
||||
: mediaType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
|
||||
var genericProperty = new XElement("GenericProperty",
|
||||
new XElement("Name", propertyType.Name),
|
||||
new XElement("Alias", propertyType.Alias),
|
||||
@@ -382,14 +385,14 @@ namespace Umbraco.Core.Services
|
||||
structure.Add(new XElement("DocumentType", allowedType.Alias));
|
||||
}
|
||||
|
||||
var genericProperties = new XElement("GenericProperties");
|
||||
var genericProperties = new XElement("GenericProperties"); // actually, all of them
|
||||
foreach (var propertyType in contentType.PropertyTypes)
|
||||
{
|
||||
var definition = dataTypeService.GetDataTypeDefinitionById(propertyType.DataTypeDefinitionId);
|
||||
|
||||
var propertyGroup = propertyType.PropertyGroupId == null
|
||||
? null
|
||||
: contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
var propertyGroup = propertyType.PropertyGroupId == null // true generic property
|
||||
? null
|
||||
: contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
|
||||
var genericProperty = new XElement("GenericProperty",
|
||||
new XElement("Name", propertyType.Name),
|
||||
|
||||
@@ -255,7 +255,12 @@ namespace Umbraco.Core.Services
|
||||
/// </returns>
|
||||
public Attempt<OperationStatus<ITemplate, OperationStatusType>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0)
|
||||
{
|
||||
var template = new Template(contentTypeName, contentTypeAlias);
|
||||
var template = new Template(contentTypeName,
|
||||
//NOTE: We are NOT passing in the content type alias here, we want to use it's name since we don't
|
||||
// want to save template file names as camelCase, the Template ctor will clean the alias as
|
||||
// `alias.ToCleanString(CleanStringType.UnderscoreAlias)` which has been the default.
|
||||
// This fixes: http://issues.umbraco.org/issue/U4-7953
|
||||
contentTypeName);
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
|
||||
@@ -21,10 +21,11 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
Attempt<string[]> ValidateComposition(IContentTypeComposition compo);
|
||||
|
||||
Attempt<int> CreateContentTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<int> CreateMediaTypeContainer(int parentId, string name, int userId = 0);
|
||||
void SaveContentTypeContainer(EntityContainer container, int userId = 0);
|
||||
void SaveMediaTypeContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContentTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateMediaTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContentTypeContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0);
|
||||
|
||||
EntityContainer GetContentTypeContainer(int containerId);
|
||||
EntityContainer GetContentTypeContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(int[] containerIds);
|
||||
@@ -35,8 +36,8 @@ namespace Umbraco.Core.Services
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(int[] containerIds);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(string folderName, int level);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(IMediaType mediaType);
|
||||
void DeleteMediaTypeContainer(int folderId, int userId = 0);
|
||||
void DeleteContentTypeContainer(int containerId, int userId = 0);
|
||||
Attempt<OperationStatus> DeleteMediaTypeContainer(int folderId, int userId = 0);
|
||||
Attempt<OperationStatus> DeleteContentTypeContainer(int containerId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all property type aliases.
|
||||
@@ -290,5 +291,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId);
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int containerId);
|
||||
Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId);
|
||||
Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId);
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,14 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IDataTypeService : IService
|
||||
{
|
||||
Attempt<int> CreateContainer(int parentId, string name, int userId = 0);
|
||||
void SaveContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0);
|
||||
EntityContainer GetContainer(int containerId);
|
||||
EntityContainer GetContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetContainers(string folderName, int level);
|
||||
IEnumerable<EntityContainer> GetContainers(IDataTypeDefinition dataTypeDefinition);
|
||||
IEnumerable<EntityContainer> GetContainers(int[] containerIds);
|
||||
void DeleteContainer(int containerId, int userId = 0);
|
||||
Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IDataTypeDefinition"/> by its Name
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Configuration;
|
||||
using System.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
@@ -750,7 +750,7 @@ namespace Umbraco.Core.Services
|
||||
if (Deleting.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<IMedia>(media, evtMsgs), this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
//Delete children before deleting the 'possible parent'
|
||||
@@ -775,7 +775,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -794,7 +794,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IMedia>(media, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -819,7 +819,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -839,7 +839,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IMedia>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,7 +867,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -969,7 +969,7 @@ namespace Umbraco.Core.Services
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
@@ -1011,7 +1011,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -45,14 +45,25 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Static Helper methods
|
||||
|
||||
internal static OperationStatus Cancelled(EventMessages eventMessages)
|
||||
internal static Attempt<OperationStatus> Exception(EventMessages eventMessages, Exception ex)
|
||||
{
|
||||
return new OperationStatus(OperationStatusType.FailedCancelledByEvent, eventMessages);
|
||||
eventMessages.Add(new EventMessage("", ex.Message, EventMessageType.Error));
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedExceptionThrown, eventMessages), ex);
|
||||
}
|
||||
|
||||
internal static OperationStatus Success(EventMessages eventMessages)
|
||||
internal static Attempt<OperationStatus> Cancelled(EventMessages eventMessages)
|
||||
{
|
||||
return new OperationStatus(OperationStatusType.Success, eventMessages);
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, eventMessages));
|
||||
}
|
||||
|
||||
internal static Attempt<OperationStatus> Success(EventMessages eventMessages)
|
||||
{
|
||||
return Attempt.Succeed(new OperationStatus(OperationStatusType.Success, eventMessages));
|
||||
}
|
||||
|
||||
internal static Attempt<OperationStatus> NoOperation(EventMessages eventMessages)
|
||||
{
|
||||
return Attempt.Succeed(new OperationStatus(OperationStatusType.NoOperation, eventMessages));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -12,11 +12,21 @@ namespace Umbraco.Core.Services
|
||||
/// The saving was successful.
|
||||
/// </summary>
|
||||
Success = 0,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The saving has been cancelled by a 3rd party add-in
|
||||
/// </summary>
|
||||
FailedCancelledByEvent = 14
|
||||
FailedCancelledByEvent = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Failed, an exception was thrown/handled
|
||||
/// </summary>
|
||||
FailedExceptionThrown = 15,
|
||||
|
||||
/// <summary>
|
||||
/// When no operation is executed because it was not needed (i.e. deleting an item that doesn't exist)
|
||||
/// </summary>
|
||||
NoOperation = 100,
|
||||
|
||||
//TODO: In the future, we might need to add more operations statuses, potentially like 'FailedByPermissions', etc...
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -365,8 +365,7 @@ namespace Umbraco.Core.Services
|
||||
var dependencies = new HashSet<string>();
|
||||
|
||||
//Add the Master as a dependency
|
||||
if (infoElement.Element("Master") != null &&
|
||||
string.IsNullOrEmpty(infoElement.Element("Master").Value) == false)
|
||||
if (string.IsNullOrEmpty((string)infoElement.Element("Master")) == false)
|
||||
{
|
||||
dependencies.Add(infoElement.Element("Master").Value);
|
||||
}
|
||||
@@ -480,7 +479,7 @@ namespace Umbraco.Core.Services
|
||||
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
var rootFolderId = tryCreateFolder.Result;
|
||||
var rootFolderId = tryCreateFolder.Result.Entity.Id;
|
||||
current = _contentTypeService.GetContentTypeContainer(rootFolderId);
|
||||
}
|
||||
|
||||
@@ -514,7 +513,7 @@ namespace Umbraco.Core.Services
|
||||
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
return _contentTypeService.GetContentTypeContainer(tryCreateFolder.Result);
|
||||
return _contentTypeService.GetContentTypeContainer(tryCreateFolder.Result.Entity.Id);
|
||||
}
|
||||
|
||||
private IContentType CreateContentTypeFromXml(XElement documentType)
|
||||
@@ -627,7 +626,7 @@ namespace Umbraco.Core.Services
|
||||
contentType.AllowedTemplates = allowedTemplates;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(defaultTemplateElement.Value) == false)
|
||||
if (string.IsNullOrEmpty((string)defaultTemplateElement) == false)
|
||||
{
|
||||
var defaultTemplate = _fileService.GetTemplate(defaultTemplateElement.Value.ToSafeAlias());
|
||||
if (defaultTemplate != null)
|
||||
@@ -698,7 +697,7 @@ namespace Umbraco.Core.Services
|
||||
: _dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias(propertyEditorAlias);
|
||||
if (dataTypeDefinitions != null && dataTypeDefinitions.Any())
|
||||
{
|
||||
dataTypeDefinition = dataTypeDefinitions.First();
|
||||
dataTypeDefinition = dataTypeDefinitions.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
else if (legacyPropertyEditorId != Guid.Empty && dataTypeDefinition.ControlId != legacyPropertyEditorId)
|
||||
@@ -706,7 +705,7 @@ namespace Umbraco.Core.Services
|
||||
var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByControlId(legacyPropertyEditorId);
|
||||
if (dataTypeDefinitions != null && dataTypeDefinitions.Any())
|
||||
{
|
||||
dataTypeDefinition = dataTypeDefinitions.First();
|
||||
dataTypeDefinition = dataTypeDefinitions.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
else if (dataTypeDefinition.PropertyEditorAlias != propertyEditorAlias)
|
||||
@@ -714,7 +713,7 @@ namespace Umbraco.Core.Services
|
||||
var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias(propertyEditorAlias);
|
||||
if (dataTypeDefinitions != null && dataTypeDefinitions.Any())
|
||||
{
|
||||
dataTypeDefinition = dataTypeDefinitions.First();
|
||||
dataTypeDefinition = dataTypeDefinitions.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,13 +740,13 @@ namespace Umbraco.Core.Services
|
||||
var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value)
|
||||
{
|
||||
Name = property.Element("Name").Value,
|
||||
Description = property.Element("Description") != null ? property.Element("Description").Value : null,
|
||||
Description = (string)property.Element("Description"),
|
||||
Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false,
|
||||
ValidationRegExp = property.Element("Validation") != null ? property.Element("Validation").Value : null,
|
||||
ValidationRegExp = (string)property.Element("Validation"),
|
||||
SortOrder = sortOrder
|
||||
};
|
||||
|
||||
var tab = property.Element("Tab").Value;
|
||||
var tab = (string)property.Element("Tab");
|
||||
if (string.IsNullOrEmpty(tab))
|
||||
{
|
||||
contentType.AddPropertyType(propertyType);
|
||||
@@ -797,14 +796,14 @@ namespace Umbraco.Core.Services
|
||||
using (var repository = _repositoryFactory.CreateContentTypeRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IContentType>.Builder.Where(x => x.Alias == contentTypeAlias);
|
||||
var types = repository.GetByQuery(query);
|
||||
var types = repository.GetByQuery(query).ToArray();
|
||||
|
||||
if (!types.Any())
|
||||
if (types.Any() == false)
|
||||
throw new Exception(
|
||||
string.Format("No ContentType matching the passed in Alias: '{0}' was found",
|
||||
contentTypeAlias));
|
||||
|
||||
var contentType = types.First();
|
||||
var contentType = types.FirstOrDefault();
|
||||
|
||||
if (contentType == null)
|
||||
throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null",
|
||||
@@ -889,7 +888,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var dataTypeDefinitionName = dataTypeElement.Attribute("Name").Value;
|
||||
|
||||
var legacyPropertyEditorId = Guid.Empty;
|
||||
Guid legacyPropertyEditorId;
|
||||
Guid.TryParse(dataTypeElement.Attribute("Id").Value, out legacyPropertyEditorId);
|
||||
|
||||
var dataTypeDefinitionId = new Guid(dataTypeElement.Attribute("Definition").Value);
|
||||
@@ -982,7 +981,7 @@ namespace Umbraco.Core.Services
|
||||
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
current = _dataTypeService.GetContainer(tryCreateFolder.Result);
|
||||
current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
|
||||
}
|
||||
|
||||
importedFolders.Add(name, current.Id);
|
||||
@@ -1015,7 +1014,7 @@ namespace Umbraco.Core.Services
|
||||
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
|
||||
throw tryCreateFolder.Exception;
|
||||
}
|
||||
return _dataTypeService.GetContainer(tryCreateFolder.Result);
|
||||
return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
|
||||
}
|
||||
|
||||
private void SavePrevaluesFromXml(List<IDataTypeDefinition> dataTypes, IEnumerable<XElement> dataTypeElements)
|
||||
@@ -1026,23 +1025,30 @@ namespace Umbraco.Core.Services
|
||||
if (prevaluesElement == null) continue;
|
||||
|
||||
var dataTypeDefinitionName = dataTypeElement.Attribute("Name").Value;
|
||||
var dataTypeDefinition = dataTypes.First(x => x.Name == dataTypeDefinitionName);
|
||||
var dataTypeDefinition = dataTypes.FirstOrDefault(x => x.Name == dataTypeDefinitionName);
|
||||
|
||||
var valuesWithoutKeys = prevaluesElement.Elements("PreValue")
|
||||
.Where(x => ((string)x.Attribute("Alias")).IsNullOrWhiteSpace())
|
||||
.Select(x => x.Attribute("Value").Value);
|
||||
if (dataTypeDefinition != null)
|
||||
{
|
||||
var valuesWithoutKeys = prevaluesElement.Elements("PreValue")
|
||||
.Where(x => ((string) x.Attribute("Alias")).IsNullOrWhiteSpace())
|
||||
.Select(x => x.Attribute("Value").Value);
|
||||
|
||||
var valuesWithKeys = prevaluesElement.Elements("PreValue")
|
||||
.Where(x => ((string)x.Attribute("Alias")).IsNullOrWhiteSpace() == false)
|
||||
.ToDictionary(
|
||||
key => (string)key.Attribute("Alias"),
|
||||
val => new PreValue((string)val.Attribute("Value")));
|
||||
var valuesWithKeys = prevaluesElement.Elements("PreValue")
|
||||
.Where(x => ((string) x.Attribute("Alias")).IsNullOrWhiteSpace() == false)
|
||||
.ToDictionary(
|
||||
key => (string) key.Attribute("Alias"),
|
||||
val => new PreValue((string) val.Attribute("Value")));
|
||||
|
||||
//save the values with keys
|
||||
_dataTypeService.SavePreValues(dataTypeDefinition, valuesWithKeys);
|
||||
//save the values with keys
|
||||
_dataTypeService.SavePreValues(dataTypeDefinition, valuesWithKeys);
|
||||
|
||||
//save the values without keys (this is legacy)
|
||||
_dataTypeService.SavePreValues(dataTypeDefinition.Id, valuesWithoutKeys);
|
||||
//save the values without keys (this is legacy)
|
||||
_dataTypeService.SavePreValues(dataTypeDefinition.Id, valuesWithoutKeys);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn<PackagingService>("No data type found with name " + dataTypeDefinitionName + " data type pre-values will not be saved");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1329,31 +1335,31 @@ namespace Umbraco.Core.Services
|
||||
//Following xml elements are treated as nullable properties
|
||||
var useInEditorElement = macroElement.Element("useInEditor");
|
||||
var useInEditor = false;
|
||||
if (useInEditorElement != null && string.IsNullOrEmpty(useInEditorElement.Value) == false)
|
||||
if (useInEditorElement != null && string.IsNullOrEmpty((string)useInEditorElement) == false)
|
||||
{
|
||||
useInEditor = bool.Parse(useInEditorElement.Value);
|
||||
}
|
||||
var cacheDurationElement = macroElement.Element("refreshRate");
|
||||
var cacheDuration = 0;
|
||||
if (cacheDurationElement != null && string.IsNullOrEmpty(cacheDurationElement.Value) == false)
|
||||
if (cacheDurationElement != null && string.IsNullOrEmpty((string)cacheDurationElement) == false)
|
||||
{
|
||||
cacheDuration = int.Parse(cacheDurationElement.Value);
|
||||
}
|
||||
var cacheByMemberElement = macroElement.Element("cacheByMember");
|
||||
var cacheByMember = false;
|
||||
if (cacheByMemberElement != null && string.IsNullOrEmpty(cacheByMemberElement.Value) == false)
|
||||
if (cacheByMemberElement != null && string.IsNullOrEmpty((string)cacheByMemberElement) == false)
|
||||
{
|
||||
cacheByMember = bool.Parse(cacheByMemberElement.Value);
|
||||
}
|
||||
var cacheByPageElement = macroElement.Element("cacheByPage");
|
||||
var cacheByPage = false;
|
||||
if (cacheByPageElement != null && string.IsNullOrEmpty(cacheByPageElement.Value) == false)
|
||||
if (cacheByPageElement != null && string.IsNullOrEmpty((string)cacheByPageElement) == false)
|
||||
{
|
||||
cacheByPage = bool.Parse(cacheByPageElement.Value);
|
||||
}
|
||||
var dontRenderElement = macroElement.Element("dontRender");
|
||||
var dontRender = true;
|
||||
if (dontRenderElement != null && string.IsNullOrEmpty(dontRenderElement.Value) == false)
|
||||
if (dontRenderElement != null && string.IsNullOrEmpty((string)dontRenderElement) == false)
|
||||
{
|
||||
dontRender = bool.Parse(dontRenderElement.Value);
|
||||
}
|
||||
@@ -1526,23 +1532,20 @@ namespace Umbraco.Core.Services
|
||||
var dependencies = new List<string>();
|
||||
var elementCopy = tempElement;
|
||||
//Ensure that the Master of the current template is part of the import, otherwise we ignore this dependency as part of the dependency sorting.
|
||||
if (elementCopy.Element("Master") != null &&
|
||||
string.IsNullOrEmpty(elementCopy.Element("Master").Value) == false &&
|
||||
templateElements.Any(x => x.Element("Alias").Value == elementCopy.Element("Master").Value))
|
||||
if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false &&
|
||||
templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master")))
|
||||
{
|
||||
dependencies.Add(elementCopy.Element("Master").Value);
|
||||
dependencies.Add((string)elementCopy.Element("Master"));
|
||||
}
|
||||
else if (elementCopy.Element("Master") != null &&
|
||||
string.IsNullOrEmpty(elementCopy.Element("Master").Value) == false &&
|
||||
templateElements.Any(x => x.Element("Alias").Value == elementCopy.Element("Master").Value) ==
|
||||
false)
|
||||
else if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false &&
|
||||
templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master")) == false)
|
||||
{
|
||||
_logger.Info<PackagingService>(string.Format("Template '{0}' has an invalid Master '{1}', so the reference has been ignored.", elementCopy.Element("Alias").Value, elementCopy.Element("Master").Value));
|
||||
_logger.Info<PackagingService>(string.Format("Template '{0}' has an invalid Master '{1}', so the reference has been ignored.", (string)elementCopy.Element("Alias"), (string)elementCopy.Element("Master")));
|
||||
}
|
||||
|
||||
var field = new TopologicalSorter.DependencyField<XElement>
|
||||
{
|
||||
Alias = elementCopy.Element("Alias").Value,
|
||||
Alias = (string)elementCopy.Element("Alias"),
|
||||
Item = new Lazy<XElement>(() => elementCopy),
|
||||
DependsOn = dependencies.ToArray()
|
||||
};
|
||||
@@ -1564,7 +1567,7 @@ namespace Umbraco.Core.Services
|
||||
var existingTemplate = _fileService.GetTemplate(alias) as Template;
|
||||
var template = existingTemplate ?? new Template(path, templateName, alias);
|
||||
template.Content = design;
|
||||
if (masterElement != null && string.IsNullOrEmpty(masterElement.Value) == false)
|
||||
if (masterElement != null && string.IsNullOrEmpty((string)masterElement) == false)
|
||||
{
|
||||
template.MasterTemplateAlias = masterElement.Value;
|
||||
var masterTemplate = templates.FirstOrDefault(x => x.Alias == masterElement.Value);
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(entry);
|
||||
@@ -191,7 +191,7 @@ namespace Umbraco.Core.Services
|
||||
uow.Commit();
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -207,7 +207,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -218,7 +218,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -232,7 +232,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -243,7 +243,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Deleted.RaiseEvent(new DeleteEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -41,6 +41,16 @@ namespace Umbraco.Core
|
||||
ToCSharpEscapeChars[escape[0]] = escape[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes new lines and tabs
|
||||
/// </summary>
|
||||
/// <param name="txt"></param>
|
||||
/// <returns></returns>
|
||||
internal static string StripWhitespace(this string txt)
|
||||
{
|
||||
return Regex.Replace(txt, @"\s", string.Empty);
|
||||
}
|
||||
|
||||
internal static string StripFileExtension(this string fileName)
|
||||
{
|
||||
//filenames cannot contain line breaks
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
protected override bool RequiresDistributed(IEnumerable<IServerAddress> servers, ICacheRefresher refresher, MessageType dispatchType)
|
||||
{
|
||||
// we don't care if there's servers listed or not,
|
||||
// we don't care if there's servers listed or not,
|
||||
// if distributed call is enabled we will make the call
|
||||
return _initialized && DistributedEnabled;
|
||||
}
|
||||
@@ -139,18 +139,43 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
if (_released) return;
|
||||
|
||||
var coldboot = false;
|
||||
if (_lastId < 0) // never synced before
|
||||
{
|
||||
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
|
||||
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
|
||||
// server and it will need to rebuild it's own caches, eg Lucene or the xml cache file.
|
||||
_logger.Warn<DatabaseServerMessenger>("No last synced Id found, this generally means this is a new server/install. The server will rebuild its caches and indexes and then adjust it's last synced id to the latest found in the database and will start maintaining cache updates based on that id");
|
||||
_logger.Warn<DatabaseServerMessenger>("No last synced Id found, this generally means this is a new server/install."
|
||||
+ " The server will build its caches and indexes, and then adjust its last synced Id to the latest found in"
|
||||
+ " the database and maintain cache updates based on that Id.");
|
||||
|
||||
coldboot = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//check for how many instructions there are to process
|
||||
var count = _appContext.DatabaseContext.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId});
|
||||
if (count > _options.MaxProcessingInstructionCount)
|
||||
{
|
||||
//too many instructions, proceed to cold boot
|
||||
_logger.Warn<DatabaseServerMessenger>("The instruction count ({0}) exceeds the specified MaxProcessingInstructionCount ({1})."
|
||||
+ " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id"
|
||||
+ " to the latest found in the database and maintain cache updates based on that Id.",
|
||||
() => count, () => _options.MaxProcessingInstructionCount);
|
||||
|
||||
coldboot = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (coldboot)
|
||||
{
|
||||
// go get the last id in the db and store it
|
||||
// note: do it BEFORE initializing otherwise some instructions might get lost
|
||||
// when doing it before, some instructions might run twice - not an issue
|
||||
var lastId = _appContext.DatabaseContext.Database.ExecuteScalar<int>("SELECT MAX(id) FROM umbracoCacheInstruction");
|
||||
if (lastId > 0)
|
||||
SaveLastSynced(lastId);
|
||||
var maxId = _appContext.DatabaseContext.Database.ExecuteScalar<int>("SELECT MAX(id) FROM umbracoCacheInstruction");
|
||||
|
||||
//if there is a max currently, or if we've never synced
|
||||
if (maxId > 0 || _lastId < 0)
|
||||
SaveLastSynced(maxId);
|
||||
|
||||
// execute initializing callbacks
|
||||
if (_options.InitializingCallbacks != null)
|
||||
@@ -169,13 +194,13 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_syncing)
|
||||
if (_syncing)
|
||||
return;
|
||||
|
||||
if (_released)
|
||||
return;
|
||||
|
||||
if ((DateTime.UtcNow - _lastSync).Seconds <= _options.ThrottleSeconds)
|
||||
if ((DateTime.UtcNow - _lastSync).TotalSeconds <= _options.ThrottleSeconds)
|
||||
return;
|
||||
|
||||
_syncing = true;
|
||||
@@ -213,9 +238,9 @@ namespace Umbraco.Core.Sync
|
||||
private void ProcessDatabaseInstructions()
|
||||
{
|
||||
// NOTE
|
||||
// we 'could' recurse to ensure that no remaining instructions are pending in the table before proceeding but I don't think that
|
||||
// we 'could' recurse to ensure that no remaining instructions are pending in the table before proceeding but I don't think that
|
||||
// would be a good idea since instructions could keep getting added and then all other threads will probably get stuck from serving requests
|
||||
// (depending on what the cache refreshers are doing). I think it's best we do the one time check, process them and continue, if there are
|
||||
// (depending on what the cache refreshers are doing). I think it's best we do the one time check, process them and continue, if there are
|
||||
// pending requests after being processed, they'll just be processed on the next poll.
|
||||
//
|
||||
// FIXME not true if we're running on a background thread, assuming we can?
|
||||
@@ -281,7 +306,7 @@ namespace Umbraco.Core.Sync
|
||||
/// Remove old instructions from the database
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Always leave the last (most recent) record in the db table, this is so that not all instructions are removed which would cause
|
||||
/// Always leave the last (most recent) record in the db table, this is so that not all instructions are removed which would cause
|
||||
/// the site to cold boot if there's been no instruction activity for more than DaysToRetainInstructions.
|
||||
/// See: http://issues.umbraco.org/issue/U4-7643#comment=67-25085
|
||||
/// </remarks>
|
||||
@@ -290,15 +315,15 @@ namespace Umbraco.Core.Sync
|
||||
var pruneDate = DateTime.UtcNow.AddDays(-_options.DaysToRetainInstructions);
|
||||
var sqlSyntax = _appContext.DatabaseContext.SqlSyntax;
|
||||
|
||||
//NOTE: this query could work on SQL server and MySQL:
|
||||
//NOTE: this query could work on SQL server and MySQL:
|
||||
/*
|
||||
SELECT id
|
||||
FROM umbracoCacheInstruction
|
||||
WHERE utcStamp < getdate()
|
||||
WHERE utcStamp < getdate()
|
||||
AND id <> (SELECT MAX(id) FROM umbracoCacheInstruction)
|
||||
*/
|
||||
// However, this will not work on SQLCE and in fact it will be slower than the query we are
|
||||
// using if the SQL server doesn't perform it's own query optimizations (i.e. since the above
|
||||
// using if the SQL server doesn't perform it's own query optimizations (i.e. since the above
|
||||
// query could actually execute a sub query for every row found). So we've had to go with an
|
||||
// inner join which is faster and works on SQLCE but it's uglier to read.
|
||||
|
||||
@@ -331,9 +356,9 @@ namespace Umbraco.Core.Sync
|
||||
var dtos = _appContext.DatabaseContext.Database.Fetch<CacheInstructionDto>(sql);
|
||||
|
||||
if (dtos.Count == 0)
|
||||
_lastId = -1;
|
||||
_lastId = -1;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the last-synced id from file into memory.
|
||||
/// </summary>
|
||||
@@ -502,4 +527,3 @@ namespace Umbraco.Core.Sync
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides options to the <see cref="DatabaseServerMessenger"/>.
|
||||
/// </summary>
|
||||
@@ -14,9 +14,15 @@ namespace Umbraco.Core.Sync
|
||||
public DatabaseServerMessengerOptions()
|
||||
{
|
||||
DaysToRetainInstructions = 2; // 2 days
|
||||
ThrottleSeconds = 5; // 5 seconds
|
||||
ThrottleSeconds = 5; // 5 second
|
||||
MaxProcessingInstructionCount = 1000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of instructions that can be processed at startup; otherwise the server cold-boots (rebuilds its caches).
|
||||
/// </summary>
|
||||
public int MaxProcessingInstructionCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of callbacks that will be invoked if the lastsynced.txt file does not exist.
|
||||
/// </summary>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Umbraco.Core
|
||||
|
||||
/// <summary>
|
||||
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
/// of the web application.
|
||||
/// of the web application.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Core
|
||||
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
@@ -136,7 +136,7 @@ namespace Umbraco.Core
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for perforance reasons.
|
||||
/// </summary>
|
||||
@@ -190,6 +190,7 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll"
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
|
||||
{
|
||||
@@ -214,7 +215,7 @@ namespace Umbraco.Core
|
||||
"RouteDebugger,",
|
||||
"SqlCE4Umbraco,",
|
||||
"umbraco.datalayer,",
|
||||
"umbraco.interfaces,",
|
||||
"umbraco.interfaces,",
|
||||
//"umbraco.providers,",
|
||||
//"Umbraco.Web.UI,",
|
||||
"umbraco.webservices",
|
||||
@@ -230,9 +231,9 @@ namespace Umbraco.Core
|
||||
"AutoMapper,",
|
||||
"AutoMapper.",
|
||||
"AzureDirectory,",
|
||||
"itextsharp,",
|
||||
"itextsharp,",
|
||||
"UrlRewritingNet.",
|
||||
"HtmlAgilityPack,",
|
||||
"HtmlAgilityPack,",
|
||||
"MiniProfiler,",
|
||||
"Moq,",
|
||||
"nunit.framework,",
|
||||
@@ -371,7 +372,7 @@ namespace Umbraco.Core
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
//find all assembly references that are referencing the attribute type's assembly since we
|
||||
//find all assembly references that are referencing the attribute type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain a class that has this attribute.
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList);
|
||||
@@ -418,7 +419,7 @@ namespace Umbraco.Core
|
||||
foreach (var subTypesInAssembly in allAttributeTypes.GroupBy(x => x.Assembly))
|
||||
{
|
||||
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
|
||||
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
|
||||
// * We should not search for sub types if the type is static since you cannot inherit from them.
|
||||
@@ -489,7 +490,7 @@ namespace Umbraco.Core
|
||||
|
||||
/// <summary>
|
||||
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// deriving from the base type.
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
@@ -513,7 +514,7 @@ namespace Umbraco.Core
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(assignTypeFrom, assemblyList);
|
||||
@@ -560,7 +561,7 @@ namespace Umbraco.Core
|
||||
foreach (var subTypesInAssembly in allSubTypes.GroupBy(x => x.Assembly))
|
||||
{
|
||||
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
|
||||
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
|
||||
// * We should not search for sub types if the type is static since you cannot inherit from them.
|
||||
@@ -602,39 +603,69 @@ namespace Umbraco.Core
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
internal static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
return Enumerable.Empty<Type>();
|
||||
|
||||
var getAll = a.GetCustomAttribute<AllowPartiallyTrustedCallersAttribute>() == null;
|
||||
|
||||
try
|
||||
{
|
||||
//we need to detect if an assembly is partially trusted, if so we cannot go interrogating all of it's types
|
||||
//only its exported types, otherwise we'll get exceptions.
|
||||
if (a.GetCustomAttribute<AllowPartiallyTrustedCallersAttribute>() == null)
|
||||
{
|
||||
return a.GetTypes();
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.GetExportedTypes();
|
||||
}
|
||||
return getAll ? a.GetTypes() : a.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
catch (TypeLoadException ex) // GetExportedTypes *can* throw TypeLoadException!
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
|
||||
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
|
||||
{
|
||||
sb.AppendLine("Exception: " + loaderException);
|
||||
}
|
||||
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
|
||||
AppendCouldNotLoad(sb, a, getAll);
|
||||
AppendLoaderException(sb, ex);
|
||||
|
||||
// rethrow as ReflectionTypeLoadException (for consistency) with new message
|
||||
throw new ReflectionTypeLoadException(new Type[0], new Exception[] { ex }, sb.ToString());
|
||||
}
|
||||
catch (ReflectionTypeLoadException rex) // GetTypes throws ReflectionTypeLoadException
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
AppendCouldNotLoad(sb, a, getAll);
|
||||
foreach (var loaderException in rex.LoaderExceptions.WhereNotNull())
|
||||
AppendLoaderException(sb, loaderException);
|
||||
|
||||
// rethrow with new message
|
||||
throw new ReflectionTypeLoadException(rex.Types, rex.LoaderExceptions, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void AppendCouldNotLoad(StringBuilder sb, Assembly a, bool getAll)
|
||||
{
|
||||
sb.Append("Could not load ");
|
||||
sb.Append(getAll ? "all" : "exported");
|
||||
sb.Append(" types from \"");
|
||||
sb.Append(a.FullName);
|
||||
sb.AppendLine("\" due to LoaderExceptions, skipping:");
|
||||
}
|
||||
|
||||
private static void AppendLoaderException(StringBuilder sb, Exception loaderException)
|
||||
{
|
||||
sb.Append(". ");
|
||||
sb.Append(loaderException.GetType().FullName);
|
||||
|
||||
var tloadex = loaderException as TypeLoadException;
|
||||
if (tloadex != null)
|
||||
{
|
||||
sb.Append(" on ");
|
||||
sb.Append(tloadex.TypeName);
|
||||
}
|
||||
|
||||
sb.Append(": ");
|
||||
sb.Append(loaderException.Message);
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
public static Type GetTypeByName(string typeName)
|
||||
{
|
||||
|
||||
@@ -102,28 +102,16 @@
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data.Entity" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Runtime.Caching" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
@@ -175,6 +163,7 @@
|
||||
<Compile Include="Cache\IJsonCacheRefresher.cs" />
|
||||
<Compile Include="Cache\JsonCacheRefresherBase.cs" />
|
||||
<Compile Include="Cache\NullCacheProvider.cs" />
|
||||
<Compile Include="Cache\RepositoryCachePolicyBase.cs" />
|
||||
<Compile Include="Cache\SingleItemsOnlyRepositoryCachePolicy.cs" />
|
||||
<Compile Include="Cache\OnlySingleItemsRepositoryCachePolicyFactory.cs" />
|
||||
<Compile Include="Cache\PayloadCacheRefresherBase.cs" />
|
||||
@@ -188,6 +177,7 @@
|
||||
<Compile Include="CodeAnnotations\UmbracoExperimentalFeatureAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoProposedPublicAttribute.cs" />
|
||||
<Compile Include="Collections\DeepCloneableList.cs" />
|
||||
<Compile Include="Collections\ListCloneBehavior.cs" />
|
||||
<Compile Include="ConcurrentHashSet.cs" />
|
||||
<Compile Include="Configuration\BaseRest\IBaseRestSection.cs" />
|
||||
<Compile Include="Configuration\BaseRest\IExtension.cs" />
|
||||
@@ -319,6 +309,7 @@
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
|
||||
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
|
||||
<Compile Include="Dynamics\CaseInsensitiveDynamicObject.cs" />
|
||||
<Compile Include="Dynamics\DynamicInstanceHelper.cs" />
|
||||
<Compile Include="Dynamics\DynamicXmlConverter.cs" />
|
||||
<Compile Include="Events\CancellableEventArgs.cs" />
|
||||
@@ -486,10 +477,11 @@
|
||||
<Compile Include="Persistence\Repositories\PublicAccessRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskTypeRepository.cs" />
|
||||
<Compile Include="Profiling\StartupWebProfilerProvider.cs" />
|
||||
<Compile Include="PropertyEditors\DecimalValidator.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\GridValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\DecimalValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\LabelValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\ImageCropperValueConverter.cs" />
|
||||
<Compile Include="Publishing\UnPublishedStatusType.cs" />
|
||||
<Compile Include="Publishing\UnPublishStatus.cs" />
|
||||
<Compile Include="Security\BackOfficeClaimsIdentityFactory.cs" />
|
||||
@@ -501,6 +493,7 @@
|
||||
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
|
||||
<Compile Include="Security\MembershipPasswordHasher.cs" />
|
||||
<Compile Include="SemVersionExtensions.cs" />
|
||||
<Compile Include="Serialization\NoTypeConverterJsonConverter.cs" />
|
||||
<Compile Include="ServiceProviderExtensions.cs" />
|
||||
<Compile Include="IO\UmbracoMediaFile.cs" />
|
||||
<Compile Include="Logging\DebugDiagnosticsLogger.cs" />
|
||||
@@ -522,6 +515,7 @@
|
||||
<Compile Include="Services\IServerRegistrationService.cs" />
|
||||
<Compile Include="Services\ITaskService.cs" />
|
||||
<Compile Include="Services\LocalizedTextServiceSupplementaryFileSource.cs" />
|
||||
<Compile Include="Models\MediaExtensions.cs" />
|
||||
<Compile Include="Services\MigrationEntryService.cs" />
|
||||
<Compile Include="Services\MoveOperationStatusType.cs" />
|
||||
<Compile Include="Services\PublicAccessService.cs" />
|
||||
@@ -1413,7 +1407,9 @@
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="FileResources\BlockingWeb.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\umbraco.interfaces\umbraco.interfaces.csproj">
|
||||
@@ -1429,11 +1425,6 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
|
||||
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
|
||||
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
|
||||
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net45" />
|
||||
@@ -19,5 +15,5 @@
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
<package id="semver" version="1.1.2" targetFramework="net45" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net4" />
|
||||
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net4" />
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -72,7 +72,7 @@
|
||||
<system.data>
|
||||
<DbProviderFactories>
|
||||
<remove invariant="System.Data.SqlServerCe.4.0" />
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
|
||||
<remove invariant="MySql.Data.MySqlClient" />
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
|
||||
</DbProviderFactories>
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Tests.Cache
|
||||
[Test]
|
||||
public void Clones_List()
|
||||
{
|
||||
var original = new DeepCloneableList<DeepCloneableListTests.TestClone>();
|
||||
var original = new DeepCloneableList<DeepCloneableListTests.TestClone>(ListCloneBehavior.Always);
|
||||
original.Add(new DeepCloneableListTests.TestClone());
|
||||
original.Add(new DeepCloneableListTests.TestClone());
|
||||
original.Add(new DeepCloneableListTests.TestClone());
|
||||
|
||||
@@ -120,5 +120,37 @@ namespace Umbraco.Tests.Cache
|
||||
Assert.IsTrue(cacheCleared);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void If_Removes_Throws_Cache_Is_Removed()
|
||||
{
|
||||
var cacheCleared = false;
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
cache.Setup(x => x.ClearCacheItem(It.IsAny<string>()))
|
||||
.Callback(() =>
|
||||
{
|
||||
cacheCleared = true;
|
||||
});
|
||||
|
||||
var defaultPolicy = new DefaultRepositoryCachePolicy<AuditItem, object>(cache.Object, new RepositoryCachePolicyOptions());
|
||||
try
|
||||
{
|
||||
using (defaultPolicy)
|
||||
{
|
||||
defaultPolicy.Remove(new AuditItem(1, "blah", AuditType.Copy, 123), item =>
|
||||
{
|
||||
throw new Exception("blah!");
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//we need this catch or nunit throw up
|
||||
}
|
||||
finally
|
||||
{
|
||||
Assert.IsTrue(cacheCleared);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user