Compare commits
184 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16d98488e4 | |||
| 5a862f5c64 | |||
| caf41b74b8 | |||
| e858f4ff1e | |||
| 851961ef2b | |||
| c139c5d93e | |||
| c4603ee5cd | |||
| 1e9d1007b6 | |||
| f23af85253 | |||
| b0c5d16ba7 | |||
| cd5581bef6 | |||
| 7d8da56dcb | |||
| 0501b181ce | |||
| 3134668cec | |||
| a8cc8fa688 | |||
| cf2217cfe1 | |||
| e88e809e29 | |||
| c5559d7721 | |||
| 771e216813 | |||
| d33cc29f98 | |||
| b98fbbc75d | |||
| aba1862811 | |||
| 2f53698bc5 | |||
| e0e12d5773 | |||
| 2e96de5449 | |||
| c5bce3b8cc | |||
| b4286a7d4e | |||
| 31e018c045 | |||
| 50b71faff9 | |||
| 033fd1b7ff | |||
| 2621b25fd3 | |||
| 61055380c5 | |||
| adf09d925f | |||
| 12170fd787 | |||
| c32cae16db | |||
| 437d1b759b | |||
| f46811ff67 | |||
| 6d50b46bd8 | |||
| a51bf232ec | |||
| fd19411e65 | |||
| 7ac7bb9714 | |||
| 021cac9ca5 | |||
| 949447c25f | |||
| 99d7bf91b7 | |||
| a92c232178 | |||
| 30901446e1 | |||
| d772336c0f | |||
| f673cb024a | |||
| c4046ecb32 | |||
| 7823609500 | |||
| a88cb3f724 | |||
| 536b8ee921 | |||
| 3bf1041041 | |||
| fee23fac0a | |||
| cf6775ec31 | |||
| 1a13366cc9 | |||
| 595b039ebe | |||
| e6406e9757 | |||
| bf65bf5bab | |||
| 306d83cbd6 | |||
| 1da901be96 | |||
| d953966248 | |||
| 2f679a52f4 | |||
| ad8ab9f46e | |||
| 9b344a5a69 | |||
| 0a28bdafc2 | |||
| 7aa1f480c9 | |||
| 998f031877 | |||
| ac7cb8febe | |||
| 6e166bdba7 | |||
| 1f2e46a195 | |||
| bb22f5a283 | |||
| dcac5d4709 | |||
| 0e4e12d0ba | |||
| 9118701669 | |||
| 58758e7a41 | |||
| 4a516f7da9 | |||
| bf8add4f8d | |||
| 9940b78a57 | |||
| 8371105c10 | |||
| 53c0bd6938 | |||
| a768fe5bb3 | |||
| d9c66cd4b3 | |||
| 5b693f9310 | |||
| 40ebc1295c | |||
| 51660d918c | |||
| 15aa6fc4b8 | |||
| b9088c9ac0 | |||
| 49cf0f98ce | |||
| d8a3e00440 | |||
| c309e18f13 | |||
| cde3c42cec | |||
| f13ddddc16 | |||
| 89235f707c | |||
| a569796adb | |||
| 81600f0f3c | |||
| 74ccd79408 | |||
| 424ff02734 | |||
| 80bd8d962b | |||
| 956364decd | |||
| 6133e8f8c2 | |||
| bcb7561e74 | |||
| 83f4c0262e | |||
| 15222e176e | |||
| 84dd7dc61a | |||
| ff5dadde53 | |||
| ded82611a7 | |||
| 6a8cb5e123 | |||
| 09428d703c | |||
| a0541b000e | |||
| 668935548d | |||
| 14141fcaa5 | |||
| 7c5942b05f | |||
| 8b4d4e3189 | |||
| 4f008f5848 | |||
| 1a40ccc838 | |||
| e80963093d | |||
| 0749124f45 | |||
| bef970437a | |||
| dda36f0147 | |||
| caad775399 | |||
| 7a7720c460 | |||
| b2aeb835d5 | |||
| 8dd950bd52 | |||
| e2881e07d1 | |||
| 71de4dc7de | |||
| e22476f54a | |||
| 20ae16b2d7 | |||
| 9e466971af | |||
| 3c6029c969 | |||
| a4a0de3503 | |||
| 217267bf94 | |||
| 4748366766 | |||
| ab00782d84 | |||
| d19d1b3a18 | |||
| 30cfa4c0ae | |||
| d028ee2c3e | |||
| a60e2318ad | |||
| f642a7fd63 | |||
| d1d54d8e84 | |||
| bbeedb6c1b | |||
| 4745995f92 | |||
| c66aca2d41 | |||
| af148a4544 | |||
| d7ea8e02d6 | |||
| 58814d4ac2 | |||
| bd1dc4f88d | |||
| 67c1cc44c5 | |||
| b680f87c12 | |||
| 8db6633c91 | |||
| 3e5128147c | |||
| b5329ace3b | |||
| e1a134f587 | |||
| bbe6194b06 | |||
| d76fd7d25e | |||
| e020989577 | |||
| 7258964bb7 | |||
| bcc2424577 | |||
| 221bfa5f3d | |||
| 85a74e4fa7 | |||
| a8858ecfdd | |||
| 0dc00a62e2 | |||
| 3b26834484 | |||
| aee10348e5 | |||
| d0fc3ddba5 | |||
| 3aadca167f | |||
| 3a92c26a7f | |||
| ff21379547 | |||
| aed4c1faed | |||
| 48bbf1ecb2 | |||
| c500d29029 | |||
| 2c8fe5a130 | |||
| d737afa327 | |||
| ec6cb4520c | |||
| 3626d5b79d | |||
| 980e8e84a6 | |||
| fb764641c5 | |||
| b94cee68e7 | |||
| b67fbbcbd8 | |||
| 4d3eef1124 | |||
| b7f7775b89 | |||
| 366697f4eb | |||
| 987644379e | |||
| 067268a96e |
@@ -299,6 +299,10 @@
|
||||
</Target>
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<PropertyGroup>
|
||||
<NewVersion>$(BUILD_RELEASE)</NewVersion>
|
||||
<NewVersion Condition="'$(BUILD_COMMENT)'!=''">$(BUILD_RELEASE)-$(BUILD_COMMENT)</NewVersion>
|
||||
</PropertyGroup>
|
||||
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
|
||||
<FileUpdate
|
||||
Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
@@ -308,5 +312,9 @@
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="CurrentComment { get { return "([a-zA-Z]+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
<XmlPoke XmlInputPath=".\NuSpecs\build\UmbracoCms.targets"
|
||||
Namespaces="<Namespace Prefix='x' Uri='http://schemas.microsoft.com/developer/msbuild/2003' />"
|
||||
Query="//x:UmbracoVersion"
|
||||
Value="$(NewVersion)" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -4,7 +4,7 @@
|
||||
<id>UmbracoCms.Core</id>
|
||||
<version>6.2.0</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Morten Christensen</authors>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
@@ -15,17 +15,20 @@
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="4.0" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="4.0" />
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.0,5.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[4.0.30506,5.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.Client" version="[4.0.30506, 5.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.0.0, 3.0.0)" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.6.5]" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.7.0, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.7.0, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.7.1.2, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.7.0.4, 2.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[4.5.11, 6.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<id>UmbracoCms</id>
|
||||
<version>6.1.2</version>
|
||||
<title>Umbraco Cms</title>
|
||||
<authors>Morten Christensen</authors>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
@@ -19,11 +19,9 @@
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="Content\bin\amd64" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="Content\bin\x86" />
|
||||
<file src="..\_BuildOutput\Configs\**" target="Content\config" exclude="..\_BuildOutput\Configs\Web.config.transform" />
|
||||
<file src="..\_BuildOutput\WebApp\css\**" target="Content\css" />
|
||||
<file src="..\_BuildOutput\WebApp\macroScripts\**" target="Content\macroScripts" />
|
||||
<file src="..\_BuildOutput\WebApp\macroScripts\**" target="Content\macroScripts" exclude="..\_BuildOutput\WebApp\macroScripts\Web.config" />
|
||||
<file src="..\_BuildOutput\WebApp\masterpages\**" target="Content\masterpages" />
|
||||
<file src="..\_BuildOutput\WebApp\media\**" target="Content\media" />
|
||||
<file src="..\_BuildOutput\WebApp\scripts\**" target="Content\scripts" />
|
||||
@@ -32,15 +30,15 @@
|
||||
<file src="..\_BuildOutput\WebApp\xslt\**" target="Content\xslt" />
|
||||
<file src="..\_BuildOutput\WebApp\default.aspx" target="Content\default.aspx" />
|
||||
<file src="..\_BuildOutput\WebApp\Web.config" target="Content\Web.config" />
|
||||
<file src="..\_BuildOutput\WebApp\Global.asax" target="Content\Global.asax" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Code\**" target="UmbracoFiles\App_Code" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Data\**" target="UmbracoFiles\App_Data" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Plugins\**" target="UmbracoFiles\App_Plugins" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Plugins\**" target="UmbracoFiles\App_Plugins" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="UmbracoFiles\bin\amd64" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="UmbracoFiles\bin\x86" />
|
||||
<file src="..\_BuildOutput\WebApp\config\splashes\**" target="UmbracoFiles\config\splashes" />
|
||||
<file src="..\_BuildOutput\WebApp\install\**" target="UmbracoFiles\install" />
|
||||
<file src="..\_BuildOutput\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
|
||||
<file src="..\_BuildOutput\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
|
||||
<file src="..\_BuildOutput\WebApp\Global.asax" target="UmbracoFiles\Global.asax" />
|
||||
<file src="..\_BuildOutput\WebApp\Web.config" target="UmbracoFiles\Web.config" />
|
||||
<file src="tools\install.ps1" target="tools\install.ps1" />
|
||||
<file src="tools\Readme.txt" target="tools\Readme.txt" />
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<UmbracoVersion>6.2.0</UmbracoVersion>
|
||||
</PropertyGroup>
|
||||
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
|
||||
<PropertyGroup>
|
||||
<UmbracoFilesFolder>..\packages\UmbracoCms.$(UmbracoVersion)\UmbracoFiles\</UmbracoFilesFolder>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="%(UmbracoFiles.FullPath)" DestinationFiles="%(RecursiveDir)%(Filename)%(Extension)" Condition="!Exists('%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
</Target>
|
||||
<Target Name="AddUmbracoFilesToOutput">
|
||||
<!-- With help from: http://blog.samstephens.co.nz/2010-10-18/msbuild-including-extra-files-multiple-builds/ -->
|
||||
<ItemGroup>
|
||||
<CustomFilesToInclude Include=".\App_Browsers\**\*">
|
||||
<Dir>App_Browsers</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\App_Code\**\*">
|
||||
<Dir>App_Code</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\App_Plugins\**\*">
|
||||
<Dir>App_Plugins</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\bin\amd64\**\*">
|
||||
<Dir>bin\amd64</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\bin\x86\**\*">
|
||||
<Dir>bin\x86</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\Config\Splashes\**\*">
|
||||
<Dir>Config\Splashes</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\umbraco\**\*">
|
||||
<Dir>umbraco</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\umbraco_client\**\*">
|
||||
<Dir>umbraco_client</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\Global.asax">
|
||||
<Dir>.</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<FilesForPackagingFromProject Include="@(CustomFilesToInclude)">
|
||||
<DestinationRelativePath>%(CustomFilesToInclude.Dir)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="AddUmbracoFilesToOutput">
|
||||
<ItemGroup>
|
||||
<UmbracoFiles Include=".\umbraco\**\*;" />
|
||||
<UmbracoClientFiles Include=".\umbraco_client\**\*;" />
|
||||
<AppBrowsersFiles Include=".\App_Browsers\**\*" />
|
||||
<FilesForPackagingFromProject Include="%(UmbracoFiles.Identity)">
|
||||
<DestinationRelativePath>umbraco\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
<FilesForPackagingFromProject Include="%(UmbracoClientFiles.Identity)">
|
||||
<DestinationRelativePath>umbraco_client\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
<FilesForPackagingFromProject Include="%(AppBrowsersFiles.Identity)">
|
||||
<DestinationRelativePath>App_Browsers\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<CopyAllFilesToSingleFolderForPackageDependsOn>
|
||||
AddUmbracoFilesToOutput;
|
||||
$(CopyAllFilesToSingleFolderForPackageDependsOn);
|
||||
</CopyAllFilesToSingleFolderForPackageDependsOn>
|
||||
|
||||
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
AddUmbracoFilesToOutput;
|
||||
$(CopyAllFilesToSingleFolderForPackageDependsOn);
|
||||
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="AddUmbracoFilesToOutput">
|
||||
<ItemGroup>
|
||||
<UmbracoFiles Include=".\umbraco\**\*;" />
|
||||
<UmbracoClientFiles Include=".\umbraco_client\**\*;" />
|
||||
<AppBrowsersFiles Include=".\App_Browsers\**\*" />
|
||||
<FilesForPackagingFromProject Include="%(UmbracoFiles.Identity)">
|
||||
<DestinationRelativePath>umbraco\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
<FilesForPackagingFromProject Include="%(UmbracoClientFiles.Identity)">
|
||||
<DestinationRelativePath>umbraco_client\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
<FilesForPackagingFromProject Include="%(AppBrowsersFiles.Identity)">
|
||||
<DestinationRelativePath>App_Browsers\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<CopyAllFilesToSingleFolderForPackageDependsOn>
|
||||
AddUmbracoFilesToOutput;
|
||||
$(CopyAllFilesToSingleFolderForPackageDependsOn);
|
||||
</CopyAllFilesToSingleFolderForPackageDependsOn>
|
||||
|
||||
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
AddUmbracoFilesToOutput;
|
||||
$(CopyAllFilesToSingleFolderForPackageDependsOn);
|
||||
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="AddUmbracoFilesToOutput">
|
||||
<ItemGroup>
|
||||
<UmbracoFiles Include=".\umbraco\**\*;" />
|
||||
<UmbracoClientFiles Include=".\umbraco_client\**\*;" />
|
||||
<AppBrowsersFiles Include=".\App_Browsers\**\*" />
|
||||
<FilesForPackagingFromProject Include="%(UmbracoFiles.Identity)">
|
||||
<DestinationRelativePath>umbraco\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
<FilesForPackagingFromProject Include="%(UmbracoClientFiles.Identity)">
|
||||
<DestinationRelativePath>umbraco_client\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
<FilesForPackagingFromProject Include="%(AppBrowsersFiles.Identity)">
|
||||
<DestinationRelativePath>App_Browsers\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
|
||||
</FilesForPackagingFromProject>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,8 +1,17 @@
|
||||
A note about running Umbraco from Visual Studio.
|
||||
|
||||
When upgrading your website using nuget a backup of config files and web.config will be created. Only the web.config will
|
||||
be overwritten by default to ensure that it has the necessary settings from the current release. This means that you'll
|
||||
have to merge the files if you made any changes to the previous config files.
|
||||
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).
|
||||
We will overwrite Web.config anyway but we keep a backup in the App_Data\NuGetBackup folder. There you'll
|
||||
find a folder with the current date and time in which the backup has been placed. Make sure to merge the
|
||||
new file with the old backup files before you proceed.
|
||||
The web.config will be overwritten by default to ensure that it has the necessary settings from the current release.
|
||||
|
||||
We've also overwritten all the files in the Umbraco and Umbraco_Client folder, these have also been backed up in
|
||||
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or a package
|
||||
might have added. Only the existing files were overwritten. If you customized anything then make sure to do a compare
|
||||
and merge with the NuGetBackup folder.
|
||||
|
||||
The config files found in the config folder will usually not be changed for patch releases, so they can usually be skipped,
|
||||
but the web.config will have to have its previous "umbracoConfigurationStatus"-appsetting and "umbracoDbDSN" connection string
|
||||
copied over (as a minimum).
|
||||
@@ -10,8 +19,8 @@ copied over (as a minimum).
|
||||
This nuget package includes build targets that extends the creation of a deploy package, which is generated by
|
||||
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
|
||||
Publish this won't affect you.
|
||||
These folders will now be automatically included when creating a deploy package or publishing to the file system:
|
||||
umbraco and umbraco_client.
|
||||
These things will now be automatically included when creating a deploy package or publishing to the file system:
|
||||
umbraco, umbraco_client, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.org:
|
||||
http://our.umbraco.org/contribute/releases
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
|
||||
if ($project) {
|
||||
# Create a backup of extisting umbraco config files
|
||||
$configPath = Join-Path (Split-Path $project.FullName -Parent) "\config"
|
||||
$backupPath = Join-Path $configPath "\backup"
|
||||
Get-ChildItem -path $configPath |
|
||||
Where -filterscript {($_.Name.EndsWith("config"))} | Foreach-Object {
|
||||
$newFileName = Join-Path $backupPath $_.Name.replace(".config",".config.backup")
|
||||
New-Item -ItemType File -Path $newFileName -Force
|
||||
Copy-Item $_.FullName $newFileName -Force
|
||||
}
|
||||
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create backup folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
|
||||
# Create a backup of original web.config
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
$webConfigSource = Join-Path $projectDestinationPath "web.config"
|
||||
$webConfigDestination = Join-Path $projectDestinationPath "web.config.backup"
|
||||
Copy-Item $webConfigSource $webConfigDestination
|
||||
|
||||
# Copy umbraco files from package to project folder
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
$umbracoFilesPath = Join-Path $rootPath "UmbracoFiles\*"
|
||||
Copy-Item $umbracoFilesPath $projectDestinationPath -recurse -force
|
||||
$webConfigSource = Join-Path $projectDestinationPath "Web.config"
|
||||
Copy-Item $webConfigSource $backupPath -Force
|
||||
|
||||
# Copy Web.config from package to project folder
|
||||
$umbracoFilesPath = Join-Path $rootPath "UmbracoFiles\Web.config"
|
||||
Copy-Item $umbracoFilesPath $projectDestinationPath -Force
|
||||
|
||||
# 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"
|
||||
Copy-Item $umbracoFolder $backupPath -Force
|
||||
robocopy $umbracoFolderSource $umbracoFolder /e /xf UI.xml
|
||||
}
|
||||
|
||||
$umbracoClientFolder = Join-Path $projectDestinationPath "Umbraco_Client"
|
||||
if(Test-Path $umbracoClientFolder) {
|
||||
$umbracoClientFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco_Client"
|
||||
Copy-Item $umbracoClientFolder $backupPath -Force
|
||||
robocopy $umbracoFolderSource $umbracoClientFolder /e
|
||||
}
|
||||
# Open readme.txt file
|
||||
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core
|
||||
|
||||
@@ -53,5 +53,6 @@ namespace Umbraco.Core.Cache
|
||||
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
public const string DataTypePreValuesCacheKey = "UmbracoPreVal";
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,12 @@ namespace Umbraco.Core.Cache
|
||||
return result.Select(x => x.TryConvertTo<T>().Result);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetCacheItemsByKeyExpression<T>(this ICacheProvider provider, string regexString)
|
||||
{
|
||||
var result = provider.GetCacheItemsByKeyExpression(regexString);
|
||||
return result.Select(x => x.TryConvertTo<T>().Result);
|
||||
}
|
||||
|
||||
public static T GetCacheItem<T>(this ICacheProvider provider, string cacheKey)
|
||||
{
|
||||
var result = provider.GetCacheItem(cacheKey);
|
||||
|
||||
@@ -171,6 +171,26 @@ namespace Umbraco.Core.Cache
|
||||
select c.Value).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
|
||||
{
|
||||
var found = new List<object>();
|
||||
foreach (var item in DictionaryCache)
|
||||
{
|
||||
var c = new DictionaryItemWrapper(item);
|
||||
var s = c.Key as string;
|
||||
if (s != null)
|
||||
{
|
||||
var withoutPrefix = s.TrimStart(string.Format("{0}-", CacheItemPrefix));
|
||||
if (Regex.IsMatch(withoutPrefix, regexString))
|
||||
{
|
||||
found.Add(c.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
|
||||
@@ -16,7 +16,15 @@ namespace Umbraco.Core.Cache
|
||||
void ClearCacheByKeySearch(string keyStartsWith);
|
||||
void ClearCacheByKeyExpression(string regexString);
|
||||
IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith);
|
||||
IEnumerable<object> GetCacheItemsByKeyExpression(string regexString);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an item with a given key
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
object GetCacheItem(string cacheKey);
|
||||
|
||||
object GetCacheItem(string cacheKey, Func<object> getCacheItem);
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,11 @@ namespace Umbraco.Core.Cache
|
||||
return Enumerable.Empty<object>();
|
||||
}
|
||||
|
||||
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
|
||||
{
|
||||
return Enumerable.Empty<object>();
|
||||
}
|
||||
|
||||
public virtual object GetCacheItem(string cacheKey)
|
||||
{
|
||||
return default(object);
|
||||
|
||||
@@ -114,6 +114,13 @@ namespace Umbraco.Core.Cache
|
||||
select c.Value).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
|
||||
{
|
||||
return (from c in MemoryCache
|
||||
where Regex.IsMatch(c.Key, regexString)
|
||||
select c.Value).ToList();
|
||||
}
|
||||
|
||||
public virtual object GetCacheItem(string cacheKey)
|
||||
{
|
||||
var result = MemoryCache.Get(cacheKey);
|
||||
|
||||
@@ -59,6 +59,13 @@ namespace Umbraco.Core.Cache
|
||||
select c.Value).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
|
||||
{
|
||||
return (from KeyValuePair<string, object> c in StaticCache
|
||||
where Regex.IsMatch(c.Key, regexString)
|
||||
select c.Value).ToList();
|
||||
}
|
||||
|
||||
public virtual object GetCacheItem(string cacheKey)
|
||||
{
|
||||
var result = StaticCache[cacheKey];
|
||||
|
||||
@@ -5,11 +5,13 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
@@ -265,7 +267,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfiguredMembershipProvidersLegacyEncoding(Constants.Conventions.Member.UmbracoMemberProviderName);
|
||||
return IsConfiguredMembershipProviderUsingLegacyEncoding(Constants.Conventions.Member.UmbracoMemberProviderName);
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -281,11 +283,11 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfiguredMembershipProvidersLegacyEncoding(Constants.Conventions.User.UmbracoUsersProviderName);
|
||||
return IsConfiguredMembershipProviderUsingLegacyEncoding(UmbracoSettings.DefaultBackofficeProvider);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetMembershipProvidersLegacyEncoding(Constants.Conventions.User.UmbracoUsersProviderName, value);
|
||||
SetMembershipProvidersLegacyEncoding(UmbracoSettings.DefaultBackofficeProvider, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,22 +368,17 @@ namespace Umbraco.Core.Configuration
|
||||
|
||||
webConfigXml.Save(webConfigFilename, SaveOptions.DisableFormatting);
|
||||
}
|
||||
|
||||
private static bool ConfiguredMembershipProvidersLegacyEncoding(string providerName)
|
||||
|
||||
private static bool IsConfiguredMembershipProviderUsingLegacyEncoding(string providerName)
|
||||
{
|
||||
var webConfigFilename = GetFullWebConfigFileName();
|
||||
var webConfigXml = XDocument.Load(webConfigFilename, LoadOptions.PreserveWhitespace);
|
||||
//check if this can even be configured.
|
||||
var membershipProvider = Membership.Providers[providerName] as MembershipProviderBase;
|
||||
if (membershipProvider == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var membershipConfigs = webConfigXml.XPathSelectElements("configuration/system.web/membership/providers/add").ToList();
|
||||
|
||||
var provider = membershipConfigs.SingleOrDefault(c => c.Attribute("name") != null && c.Attribute("name").Value == providerName);
|
||||
|
||||
var useLegacyEncodingAttribute = provider.Attribute("useLegacyEncoding");
|
||||
|
||||
bool useLegacyEncoding;
|
||||
bool.TryParse(useLegacyEncodingAttribute.Value, out useLegacyEncoding);
|
||||
|
||||
return useLegacyEncoding;
|
||||
return membershipProvider.UseLegacyEncoding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -658,7 +658,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
string defaultProvider = GetKey("/settings/providers/users/DefaultBackofficeProvider");
|
||||
if (String.IsNullOrEmpty(defaultProvider))
|
||||
defaultProvider = Constants.Conventions.User.UmbracoUsersProviderName;
|
||||
defaultProvider = "UsersMembershipProvider";
|
||||
|
||||
return defaultProvider;
|
||||
}
|
||||
@@ -1083,7 +1083,7 @@ namespace Umbraco.Core.Configuration
|
||||
bool globalPreviewEnabled = false;
|
||||
string value = GetKey("/settings/content/GlobalPreviewStorageEnabled");
|
||||
if (bool.TryParse(value, out globalPreviewEnabled))
|
||||
return !globalPreviewEnabled;
|
||||
return globalPreviewEnabled;
|
||||
// Return default
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -93,20 +93,10 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Image = "Image";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constants for Umbraco user
|
||||
/// </summary>
|
||||
public static class User
|
||||
{
|
||||
public static readonly string UmbracoUsersProviderName = "UsersMembershipProvider";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constants for Umbraco Member property aliases.
|
||||
/// </summary>
|
||||
|
||||
/// </summary>
|
||||
public static class Member
|
||||
{
|
||||
public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
|
||||
@@ -116,63 +106,63 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Property alias for a Members Password Question
|
||||
/// </summary>
|
||||
public const string PasswordQuestion = "umbracoPasswordRetrievalQuestionPropertyTypeAlias";
|
||||
public const string PasswordQuestion = "umbracoMemberPasswordRetrievalQuestion";
|
||||
|
||||
public const string PasswordQuestionLabel = "Password Question";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for Members Password Answer
|
||||
/// </summary>
|
||||
public const string PasswordAnswer = "umbracoPasswordRetrievalAnswerPropertyTypeAlias";
|
||||
public const string PasswordAnswer = "umbracoMemberPasswordRetrievalAnswer";
|
||||
|
||||
public const string PasswordAnswerLabel = "Password Answer";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Comments on a Member
|
||||
/// </summary>
|
||||
public const string Comments = "umbracoCommentPropertyTypeAlias";
|
||||
public const string Comments = "umbracoMemberComments";
|
||||
|
||||
public const string CommentsLabel = "Comments";
|
||||
public const string CommentsLabel = "Comments";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Approved boolean of a Member
|
||||
/// </summary>
|
||||
public const string IsApproved = "umbracoApprovePropertyTypeAlias";
|
||||
public const string IsApproved = "umbracoMemberApproved";
|
||||
|
||||
public const string IsApprovedLabel = "Is Approved";
|
||||
public const string IsApprovedLabel = "Is Approved";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Locked out boolean of a Member
|
||||
/// </summary>
|
||||
public const string IsLockedOut = "umbracoLockPropertyTypeAlias";
|
||||
public const string IsLockedOut = "umbracoMemberLockedOut";
|
||||
|
||||
public const string IsLockedOutLabel = "Is Locked Out";
|
||||
public const string IsLockedOutLabel = "Is Locked Out";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the last date the Member logged in
|
||||
/// </summary>
|
||||
public const string LastLoginDate = "umbracoLastLoginPropertyTypeAlias";
|
||||
public const string LastLoginDate = "umbracoMemberLastLogin";
|
||||
|
||||
public const string LastLoginDateLabel = "Last Login Date";
|
||||
public const string LastLoginDateLabel = "Last Login Date";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the last date a Member changed its password
|
||||
/// </summary>
|
||||
public const string LastPasswordChangeDate = "umbracoMemberLastPasswordChange";
|
||||
public const string LastPasswordChangeDate = "umbracoMemberLastPasswordChangeDate";
|
||||
|
||||
public const string LastPasswordChangeDateLabel = "Last Password Change Date";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the last date a Member was locked out
|
||||
/// </summary>
|
||||
public const string LastLockoutDate = "umbracoMemberLastLockout";
|
||||
public const string LastLockoutDate = "umbracoMemberLastLockoutDate";
|
||||
|
||||
public const string LastLockoutDateLabel = "Last Lockout Date";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the number of failed login attemps
|
||||
/// </summary>
|
||||
public const string FailedPasswordAttempts = "umbracoFailedPasswordAttemptsPropertyTypeAlias";
|
||||
public const string FailedPasswordAttempts = "umbracoMemberFailedPasswordAttempts";
|
||||
|
||||
public const string FailedPasswordAttemptsLabel = "Failed Password Attempts";
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the constants used for Umbraco packages in the package.config xml
|
||||
/// </summary>
|
||||
public static class Packaging
|
||||
{
|
||||
public const string UmbPackageNodeName = "umbPackage";
|
||||
public const string DataTypesNodeName = "DataTypes";
|
||||
public const string PackageXmlFileName = "package.xml";
|
||||
public const string UmbracoPackageExtention = ".umb";
|
||||
public const string DataTypeNodeName = "DataType";
|
||||
public const string LanguagesNodeName = "Languages";
|
||||
public const string FilesNodeName = "Files";
|
||||
public const string StylesheetsNodeName = "Stylesheets";
|
||||
public const string TemplatesNodeName = "Templates";
|
||||
public const string OrgnameNodeName = "orgName";
|
||||
public const string NameNodeName = "Name";
|
||||
public const string TemplateNodeName = "Template";
|
||||
public const string AliasNodeName = "Alias";
|
||||
public const string DictionaryitemsNodeName = "DictionaryItems";
|
||||
public const string MacrosNodeName = "macros";
|
||||
public const string DocumentSetNodeName = "DocumentSet";
|
||||
public const string DocumentTypesNodeName = "DocumentTypes";
|
||||
public const string DocumentTypeNodeName = "DocumentType";
|
||||
public const string FileNodeName = "file";
|
||||
public const string OrgPathNodeName = "orgPath";
|
||||
public const string GuidNodeName = "guid";
|
||||
public const string StylesheetNodeName = "styleSheet";
|
||||
public const string MacroNodeName = "macro";
|
||||
public const string InfoNodeName = "info";
|
||||
public const string PackageRequirementsMajorXpath = "/package/requirements/major";
|
||||
public const string PackageRequirementsMinorXpath = "/package/requirements/minor";
|
||||
public const string PackageRequirementsPatchXpath = "/package/requirements/patch";
|
||||
public const string PackageNameXpath = "/package/name";
|
||||
public const string PackageVersionXpath = "/package/version";
|
||||
public const string PackageUrlXpath = "/package/url";
|
||||
public const string PackageLicenseXpath = "/package/license";
|
||||
public const string AuthorNameXpath = "/author/name";
|
||||
public const string AuthorWebsiteXpath = "/author/website";
|
||||
public const string ReadmeXpath = "/readme";
|
||||
public const string ControlNodeName = "control";
|
||||
public const string ActionNodeName = "Action";
|
||||
public const string ActionsNodeName = "Actions";
|
||||
public const string UndoNodeAttribute = "undo";
|
||||
public const string RunatNodeAttribute = "runat";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,7 @@ namespace Umbraco.Core
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
() => PluginManager.Current.ResolveMigrationTypes());
|
||||
() => PluginManager.Current.ResolveTypes<IMigration>());
|
||||
|
||||
// todo: remove once we drop IPropertyEditorValueConverter support.
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Configuration;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -426,6 +427,13 @@ namespace Umbraco.Core
|
||||
|
||||
if (_result == null)
|
||||
{
|
||||
|
||||
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted
|
||||
&& ProviderName == "MySql.Data.MySqlClient")
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
|
||||
}
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var dbSchema = new DatabaseSchemaCreation(database);
|
||||
_result = dbSchema.ValidateSchema();
|
||||
@@ -434,20 +442,25 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
internal Result CreateDatabaseSchemaAndData()
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
string message;
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
|
||||
// If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks
|
||||
// for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive.
|
||||
|
||||
/*
|
||||
var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
if (supportsCaseInsensitiveQueries == false)
|
||||
{
|
||||
@@ -460,8 +473,9 @@ namespace Umbraco.Core
|
||||
|
||||
return new Result { Message = message, Success = false, Percentage = "15" };
|
||||
}
|
||||
*/
|
||||
|
||||
message = GetResultMessageForMySql(supportsCaseInsensitiveQueries);
|
||||
message = GetResultMessageForMySql();
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
@@ -500,20 +514,21 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
internal Result UpgradeSchemaAndData()
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database upgrade started");
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
|
||||
var message = GetResultMessageForMySql(supportsCaseInsensitiveQueries);
|
||||
var message = GetResultMessageForMySql();
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
@@ -540,6 +555,23 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
private string GetResultMessageForMySql()
|
||||
{
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/*
|
||||
private string GetResultMessageForMySql(bool? supportsCaseInsensitiveQueries)
|
||||
{
|
||||
if (supportsCaseInsensitiveQueries == null)
|
||||
@@ -563,10 +595,16 @@ namespace Umbraco.Core
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}*/
|
||||
|
||||
private Attempt<Result> CheckReadyForInstall()
|
||||
{
|
||||
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted
|
||||
&& ProviderName == "MySql.Data.MySqlClient")
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
|
||||
}
|
||||
|
||||
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
|
||||
{
|
||||
return Attempt.Fail(new Result
|
||||
|
||||
@@ -36,42 +36,22 @@ namespace Umbraco.Core.Dynamics
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
if (!string.IsNullOrEmpty(haystack) || needles.Any())
|
||||
{
|
||||
return needles.Any(haystack.Contains);
|
||||
}
|
||||
return false;
|
||||
return StringExtensions.ContainsAny(haystack, needles);
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, params string[] needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
if (!string.IsNullOrEmpty(haystack) || needles.Length > 0)
|
||||
{
|
||||
return needles.Any(haystack.Contains);
|
||||
}
|
||||
return false;
|
||||
return StringExtensions.ContainsAny(haystack, needles);
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, StringComparison comparison, IEnumerable<string> needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
if (!string.IsNullOrEmpty(haystack) || needles.Any())
|
||||
{
|
||||
return needles.Any(value => haystack.IndexOf(value, comparison) >= 0);
|
||||
}
|
||||
return false;
|
||||
return StringExtensions.ContainsAny(haystack, needles, comparison);
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, StringComparison comparison, params string[] needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
if (!string.IsNullOrEmpty(haystack) || needles.Length > 0)
|
||||
{
|
||||
return needles.Any(value => haystack.IndexOf(value, comparison) >= 0);
|
||||
}
|
||||
return false;
|
||||
return StringExtensions.ContainsAny(haystack, needles, comparison);
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsInsensitive(this string haystack, string needle)
|
||||
|
||||
@@ -4,14 +4,14 @@ using System.Web;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
internal class PropertyResult : IPublishedProperty, IHtmlString
|
||||
internal class PropertyResult : IPublishedContentProperty, IHtmlString
|
||||
{
|
||||
private readonly IPublishedProperty _source;
|
||||
private readonly IPublishedContentProperty _source;
|
||||
private readonly string _alias;
|
||||
private readonly object _value;
|
||||
private readonly PropertyResultType _type;
|
||||
|
||||
internal PropertyResult(IPublishedProperty source, PropertyResultType type)
|
||||
internal PropertyResult(IPublishedContentProperty source, PropertyResultType type)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace Umbraco.Core
|
||||
public static IEnumerable<IEnumerable<T>> InGroupsOf<T>(this IEnumerable<T> source, int groupSize)
|
||||
{
|
||||
if (source == null)
|
||||
throw new NullReferenceException("source");
|
||||
throw new NullReferenceException("source");
|
||||
|
||||
// enumerate the source only once!
|
||||
return new InGroupsEnumerator<T>(source, groupSize).Groups();
|
||||
@@ -125,23 +126,13 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>The flatten list.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="selectChild">The select child.</param>
|
||||
/// <typeparam name="TItem">Item type</typeparam>
|
||||
/// <param name="e">The items.</param>
|
||||
/// <param name="f">The select child.</param>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")]
|
||||
public static IEnumerable<TItem> FlattenList<TItem>(this IEnumerable<TItem> items, Func<TItem, IEnumerable<TItem>> selectChild)
|
||||
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
|
||||
{
|
||||
IEnumerable<TItem> children = items != null && items.Any()
|
||||
? items.SelectMany(selectChild).FlattenList(selectChild)
|
||||
: Enumerable.Empty<TItem>();
|
||||
|
||||
if (items != null)
|
||||
{
|
||||
return items.Concat(children);
|
||||
}
|
||||
|
||||
return null;
|
||||
return e.SelectMany(c => f(c).FlattenList(f)).Concat(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Events
|
||||
/// <remarks>
|
||||
/// This is protected so that inheritors can expose it with their own name
|
||||
/// </remarks>
|
||||
protected T EventObject { get; private set; }
|
||||
protected T EventObject { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public class MoveEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
|
||||
{
|
||||
public MoveEventArgs(TEntity eventObject, bool canCancel, int parentId) : base(eventObject, canCancel)
|
||||
{
|
||||
ParentId = parentId;
|
||||
}
|
||||
public class MoveEventInfo<TEntity>
|
||||
{
|
||||
public MoveEventInfo(TEntity entity, string originalPath, int newParentId)
|
||||
{
|
||||
Entity = entity;
|
||||
OriginalPath = originalPath;
|
||||
NewParentId = newParentId;
|
||||
}
|
||||
|
||||
public MoveEventArgs(TEntity eventObject, int parentId) : base(eventObject)
|
||||
{
|
||||
ParentId = parentId;
|
||||
}
|
||||
public TEntity Entity { get; set; }
|
||||
public string OriginalPath { get; set; }
|
||||
public int NewParentId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The entity being moved
|
||||
/// </summary>
|
||||
public TEntity Entity
|
||||
{
|
||||
get { return EventObject; }
|
||||
}
|
||||
public class MoveEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="moveInfo">
|
||||
/// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation
|
||||
/// </param>
|
||||
public MoveEventArgs(bool canCancel, params MoveEventInfo<TEntity>[] moveInfo)
|
||||
: base(default(TEntity), canCancel)
|
||||
{
|
||||
if (moveInfo.FirstOrDefault() == null)
|
||||
{
|
||||
throw new ArgumentException("moveInfo argument must contain at least one item");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Id of the objects new parent.
|
||||
/// </summary>
|
||||
public int ParentId { get; private set; }
|
||||
}
|
||||
MoveInfoCollection = moveInfo;
|
||||
//assign the legacy props
|
||||
EventObject = moveInfo.First().Entity;
|
||||
ParentId = moveInfo.First().NewParentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
/// <param name="moveInfo">
|
||||
/// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation
|
||||
/// </param>
|
||||
public MoveEventArgs(params MoveEventInfo<TEntity>[] moveInfo)
|
||||
: base(default(TEntity))
|
||||
{
|
||||
if (moveInfo.FirstOrDefault() == null)
|
||||
{
|
||||
throw new ArgumentException("moveInfo argument must contain at least one item");
|
||||
}
|
||||
|
||||
MoveInfoCollection = moveInfo;
|
||||
//assign the legacy props
|
||||
EventObject = moveInfo.First().Entity;
|
||||
ParentId = moveInfo.First().NewParentId;
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload that specifies the MoveEventInfo object")]
|
||||
public MoveEventArgs(TEntity eventObject, bool canCancel, int parentId)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ParentId = parentId;
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload that specifies the MoveEventInfo object")]
|
||||
public MoveEventArgs(TEntity eventObject, int parentId)
|
||||
: base(eventObject)
|
||||
{
|
||||
ParentId = parentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all MoveEventInfo objects used to create the object
|
||||
/// </summary>
|
||||
public IEnumerable<MoveEventInfo<TEntity>> MoveInfoCollection { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The entity being moved
|
||||
/// </summary>
|
||||
[Obsolete("Retrieve the entity object from the MoveInfoCollection property instead")]
|
||||
public TEntity Entity
|
||||
{
|
||||
get { return EventObject; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Id of the object's new parent
|
||||
/// </summary>
|
||||
[Obsolete("Retrieve the ParentId from the MoveInfoCollection property instead")]
|
||||
public int ParentId { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -232,6 +232,7 @@ namespace Umbraco.Core.Models
|
||||
/// <remarks>
|
||||
/// This Property is kept internal until localization is introduced.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
internal string NodeName
|
||||
{
|
||||
get { return _nodeName; }
|
||||
@@ -248,6 +249,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Used internally to track if permissions have been changed during the saving process for this entity
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal bool PermissionsChanged
|
||||
{
|
||||
get { return _permissionsChanged; }
|
||||
@@ -314,6 +316,7 @@ namespace Umbraco.Core.Models
|
||||
PublishedState = state;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal PublishedState PublishedState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -333,26 +336,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a clone of the current entity
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IContent Clone()
|
||||
{
|
||||
var clone = (Content)this.MemberwiseClone();
|
||||
clone.Key = Guid.Empty;
|
||||
clone.Version = Guid.NewGuid();
|
||||
clone.ResetIdentity();
|
||||
|
||||
foreach (var property in clone.Properties)
|
||||
{
|
||||
property.ResetIdentity();
|
||||
property.Version = clone.Version;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current <see cref="IContent"/> entity is dirty.
|
||||
/// </summary>
|
||||
@@ -432,5 +415,47 @@ namespace Umbraco.Core.Models
|
||||
base.UpdatingEntity();
|
||||
Version = Guid.NewGuid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use DeepCloneWithResetIdentities instead")]
|
||||
public IContent Clone()
|
||||
{
|
||||
return DeepCloneWithResetIdentities();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IContent DeepCloneWithResetIdentities()
|
||||
{
|
||||
var clone = (Content)DeepClone();
|
||||
clone.Key = Guid.Empty;
|
||||
clone.Version = Guid.NewGuid();
|
||||
clone.ResetIdentity();
|
||||
|
||||
foreach (var property in clone.Properties)
|
||||
{
|
||||
property.ResetIdentity();
|
||||
property.Version = clone.Version;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Content)base.DeepClone();
|
||||
|
||||
//need to manually clone this since it's not settable
|
||||
clone._contentType = (IContentType)ContentType.DeepClone();
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,13 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Represents an abstract class for base Content properties and methods
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
[DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")]
|
||||
public abstract class ContentBase : Entity, IContentBase
|
||||
{
|
||||
protected IContentTypeComposition ContentTypeBase;
|
||||
|
||||
private Lazy<int> _parentId;
|
||||
private string _name;//NOTE Once localization is introduced this will be the localized Name of the Content/Media.
|
||||
private int _sortOrder;
|
||||
@@ -257,6 +260,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
private readonly IDictionary<string, object> _additionalData;
|
||||
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
@@ -444,6 +448,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Returns a collection of the result of the last validation process, this collection contains all invalid properties.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal IEnumerable<Property> LastInvalidProperties
|
||||
{
|
||||
get { return _lastInvalidProperties; }
|
||||
@@ -465,5 +470,6 @@ namespace Umbraco.Core.Models
|
||||
prop.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used content repository in order to add an entity to the persisted collection to be saved
|
||||
/// in a single transaction during saving an entity
|
||||
/// </summary>
|
||||
internal class ContentPreviewEntity<TContent> : ContentXmlEntity<TContent>
|
||||
where TContent : IContentBase
|
||||
{
|
||||
public ContentPreviewEntity(bool previewExists, TContent content, Func<TContent, XElement> xml)
|
||||
: base(previewExists, content, xml)
|
||||
{
|
||||
Version = content.Version;
|
||||
}
|
||||
|
||||
public Guid Version { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -120,38 +120,6 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a clone of the current entity
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IContentType Clone(string alias)
|
||||
{
|
||||
var clone = (ContentType)this.MemberwiseClone();
|
||||
clone.Alias = alias;
|
||||
clone.Key = Guid.Empty;
|
||||
var propertyGroups = this.PropertyGroups.Select(x => x.Clone()).ToList();
|
||||
clone.PropertyGroups = new PropertyGroupCollection(propertyGroups);
|
||||
clone.PropertyTypes = this.PropertyTypeCollection.Select(x => x.Clone()).ToList();
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
foreach (var propertyGroup in clone.PropertyGroups)
|
||||
{
|
||||
propertyGroup.ResetIdentity();
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
propertyType.ResetIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyType in clone.PropertyTypes.Where(x => x.HasIdentity))
|
||||
{
|
||||
propertyType.ResetIdentity();
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being saved
|
||||
@@ -173,5 +141,53 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
base.UpdatingEntity();
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (ContentType)base.DeepClone();
|
||||
var propertyGroups = PropertyGroups.Select(x => (PropertyGroup)x.DeepClone()).ToList();
|
||||
clone.PropertyGroups = new PropertyGroupCollection(propertyGroups);
|
||||
//set the property types that are not part of a group
|
||||
clone.PropertyTypes = PropertyTypeCollection
|
||||
.Where(x => x.PropertyGroupId == null)
|
||||
.Select(x => (PropertyType)x.DeepClone()).ToList();
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use DeepCloneWithResetIdentities instead")]
|
||||
public IContentType Clone(string alias)
|
||||
{
|
||||
return DeepCloneWithResetIdentities(alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IContentType DeepCloneWithResetIdentities(string alias)
|
||||
{
|
||||
var clone = (ContentType)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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -173,7 +174,8 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value.ToSafeAlias();
|
||||
//_alias = value.ToSafeAlias();
|
||||
_alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
@@ -319,7 +321,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IDictionary<string, object> _additionalData;
|
||||
private IDictionary<string, object> _additionalData;
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
|
||||
{
|
||||
private readonly List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
|
||||
private List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
|
||||
internal List<int> RemovedContentTypeKeyTracker = new List<int>();
|
||||
|
||||
protected ContentTypeCompositionBase(int parentId) : base(parentId)
|
||||
@@ -217,5 +217,17 @@ namespace Umbraco.Core.Models
|
||||
.Select(x => x.Id)
|
||||
.Union(ContentTypeComposition.SelectMany(x => x.CompositionIds()));
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (ContentTypeCompositionBase)base.DeepClone();
|
||||
|
||||
//need to manually assign since this is an internal field and will not be automatically mapped
|
||||
clone.RemovedContentTypeKeyTracker = new List<int>();
|
||||
clone._contentTypeComposition = ContentTypeComposition.Select(x => (IContentTypeComposition)x.DeepClone()).ToList();
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Represents a POCO for setting sort order on a ContentType reference
|
||||
/// </summary>
|
||||
public class ContentTypeSort : IValueObject
|
||||
public class ContentTypeSort : IValueObject, IDeepCloneable
|
||||
{
|
||||
public ContentTypeSort()
|
||||
{
|
||||
@@ -33,5 +33,36 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or sets the Alias of the ContentType
|
||||
/// </summary>
|
||||
public string Alias { get; set; }
|
||||
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
var clone = (ContentTypeSort)MemberwiseClone();
|
||||
var id = Id.Value;
|
||||
clone.Id = new Lazy<int>(() => id);
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected bool Equals(ContentTypeSort other)
|
||||
{
|
||||
return Id.Value.Equals(other.Id.Value) && string.Equals(Alias, other.Alias);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((ContentTypeSort) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Id.GetHashCode()*397) ^ Alias.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in content/media/member repositories in order to add this type of entity to the persisted collection to be saved
|
||||
/// in a single transaction during saving an entity
|
||||
/// </summary>
|
||||
internal class ContentXmlEntity<TContent> : IAggregateRoot
|
||||
where TContent : IContentBase
|
||||
{
|
||||
private readonly bool _entityExists;
|
||||
private readonly Func<TContent, XElement> _xml;
|
||||
|
||||
public ContentXmlEntity(bool entityExists, TContent content, Func<TContent, XElement> xml)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
_entityExists = entityExists;
|
||||
_xml = xml;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public ContentXmlEntity(TContent content)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public XElement Xml
|
||||
{
|
||||
get { return _xml(Content); }
|
||||
}
|
||||
public TContent Content { get; private set; }
|
||||
|
||||
public int Id
|
||||
{
|
||||
get { return Content.Id; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public Guid Key { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
public bool HasIdentity
|
||||
{
|
||||
get { return _entityExists; }
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
var clone = (ContentXmlEntity<TContent>)MemberwiseClone();
|
||||
//Automatically deep clone ref properties that are IDeepCloneable
|
||||
DeepCloneHelper.DeepCloneRefProperties(this, clone);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="output"></param>
|
||||
/// <returns></returns>
|
||||
public static void DeepCloneRefProperties(IDeepCloneable input, IDeepCloneable output)
|
||||
{
|
||||
var inputType = input.GetType();
|
||||
var outputType = output.GetType();
|
||||
|
||||
if (inputType != outputType)
|
||||
{
|
||||
throw new InvalidOperationException("Both the input and output types must be the same");
|
||||
}
|
||||
|
||||
var refProperties = inputType.GetProperties()
|
||||
.Where(x =>
|
||||
//reference type but not string
|
||||
x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|
||||
//settable
|
||||
&& x.CanWrite
|
||||
//non-indexed
|
||||
&& x.GetIndexParameters().Any() == false);
|
||||
|
||||
foreach (var propertyInfo in refProperties)
|
||||
{
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
{
|
||||
//this ref property is also deep cloneable so clone it
|
||||
var result = (IDeepCloneable)propertyInfo.GetValue(input, null);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
//set the cloned value to the property
|
||||
propertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
}
|
||||
}
|
||||
else if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
{
|
||||
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
|
||||
{
|
||||
//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);
|
||||
if (enumerable == null) continue;
|
||||
|
||||
var isUsableType = true;
|
||||
|
||||
//now clone each item
|
||||
foreach (var o in enumerable)
|
||||
{
|
||||
//first check if the item is deep cloneable and copy that way
|
||||
var dc = o as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add(dc.DeepClone());
|
||||
}
|
||||
else if (o is string || o.GetType().IsValueType)
|
||||
{
|
||||
//check if the item is a value type or a string, then we can just use it
|
||||
newList.Add(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
//this will occur if the item is not a string or value type or IDeepCloneable, in this case we cannot
|
||||
// clone each element, we'll need to skip this property, people will have to manually clone this list
|
||||
isUsableType = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if this was not usable, skip this property
|
||||
if (isUsableType == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType.IsArray)
|
||||
{
|
||||
//need to convert to array
|
||||
var arr = (object[])Activator.CreateInstance(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);
|
||||
}
|
||||
else
|
||||
{
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, newList, null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -96,5 +97,6 @@ namespace Umbraco.Core.Models
|
||||
if(ParentId == Guid.Empty)
|
||||
_parentId = new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -65,5 +65,6 @@ namespace Umbraco.Core.Models
|
||||
}, _value, ValueSelector);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
@@ -93,7 +96,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// /// Gets or sets the WasCancelled flag, which is used to track
|
||||
/// Gets or sets the WasCancelled flag, which is used to track
|
||||
/// whether some action against an entity was cancelled through some event.
|
||||
/// This only exists so we have a way to check if an event was cancelled through
|
||||
/// the new api, which also needs to take effect in the legacy api.
|
||||
@@ -155,6 +158,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity has an identity, eg. Id.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual bool HasIdentity
|
||||
{
|
||||
get
|
||||
@@ -226,5 +230,62 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
_hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode());
|
||||
return _hash.Value;
|
||||
}
|
||||
|
||||
public virtual object DeepClone()
|
||||
{
|
||||
//Memberwise clone on Entity will work since it doesn't have any deep elements
|
||||
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
|
||||
var clone = (Entity)MemberwiseClone();
|
||||
//Automatically deep clone ref properties that are IDeepCloneable
|
||||
DeepCloneHelper.DeepCloneRefProperties(this, clone);
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
|
||||
//Using data contract serializer - has issues
|
||||
|
||||
//var s = Serialize(this);
|
||||
//var d = Deserialize(s, this.GetType());
|
||||
//return d;
|
||||
|
||||
//Using binary serializer - has issues
|
||||
|
||||
//using (var memoryStream = new MemoryStream(10))
|
||||
//{
|
||||
//IFormatter formatter = new BinaryFormatter();
|
||||
//formatter.Serialize(memoryStream, this);
|
||||
//memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
//return formatter.Deserialize(memoryStream);
|
||||
//}
|
||||
}
|
||||
|
||||
// serialize/deserialize with data contracts:
|
||||
|
||||
//public static string Serialize(object obj)
|
||||
//{
|
||||
// using (var memoryStream = new MemoryStream())
|
||||
// using (var reader = new StreamReader(memoryStream))
|
||||
// {
|
||||
// var serializer = new DataContractSerializer(obj.GetType());
|
||||
// serializer.WriteObject(memoryStream, obj);
|
||||
// memoryStream.Position = 0;
|
||||
// return reader.ReadToEnd();
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static object Deserialize(string xml, Type toType)
|
||||
//{
|
||||
// using (Stream stream = new MemoryStream())
|
||||
// {
|
||||
// using (var writer = new StreamWriter(stream, Encoding.UTF8))
|
||||
// {
|
||||
// writer.Write(xml);
|
||||
// //byte[] data = Encoding.UTF8.GetBytes(xml);
|
||||
// //stream.Write(data, 0, data.Length);
|
||||
// stream.Position = 0;
|
||||
// var deserializer = new DataContractSerializer(toType);
|
||||
// return deserializer.ReadObject(stream);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// </summary>
|
||||
/// <remarks>The current database schema doesn't provide a modified date
|
||||
/// for all entities, so this will have to be changed at a later stage.</remarks>
|
||||
public interface IEntity
|
||||
public interface IEntity : IDeepCloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Id of the entity
|
||||
|
||||
@@ -3,12 +3,15 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for use to implement IRememberBeingDirty/ICanBeDirty
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class TracksChangesEntityBase : IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -6,16 +6,6 @@ using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal sealed class Folder : Entity
|
||||
{
|
||||
public Folder(string folderPath)
|
||||
{
|
||||
Path = folderPath;
|
||||
}
|
||||
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an abstract file which provides basic functionality for a File with an Alias and Name
|
||||
/// </summary>
|
||||
@@ -114,5 +104,18 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
public abstract bool IsValid();
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (File)base.DeepClone();
|
||||
|
||||
//need to manually assign since they are readonly properties
|
||||
clone._alias = Alias;
|
||||
clone._name = Name;
|
||||
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal sealed class Folder : Entity
|
||||
{
|
||||
public Folder(string folderPath)
|
||||
{
|
||||
Path = folderPath;
|
||||
}
|
||||
|
||||
public string Path { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -72,5 +72,11 @@ namespace Umbraco.Core.Models
|
||||
/// Changes the Published state of the content object
|
||||
/// </summary>
|
||||
void ChangePublishedState(PublishedState state);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IContent DeepCloneWithResetIdentities();
|
||||
}
|
||||
}
|
||||
@@ -29,5 +29,12 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="template"><see cref="ITemplate"/> to remove</param>
|
||||
/// <returns>True if template was removed, otherwise False</returns>
|
||||
bool RemoveTemplate(ITemplate template);
|
||||
|
||||
/// <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>
|
||||
IContentType DeepCloneWithResetIdentities(string newAlias);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IDeepCloneable
|
||||
{
|
||||
object DeepClone();
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ namespace Umbraco.Core.Models
|
||||
/// <para>The properties collection of an IPublishedContent instance should be read-only ie it is illegal
|
||||
/// to add properties to the collection.</para>
|
||||
/// </remarks>
|
||||
ICollection<IPublishedProperty> Properties { get; }
|
||||
ICollection<IPublishedContentProperty> Properties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property identified by its alias.
|
||||
@@ -119,7 +119,7 @@ namespace Umbraco.Core.Models
|
||||
/// <para>otherwise return a property -- that may have no value (ie <c>HasValue</c> is <c>false</c>).</para>
|
||||
/// <para>The alias is case-insensitive.</para>
|
||||
/// </remarks>
|
||||
IPublishedProperty GetProperty(string alias);
|
||||
IPublishedContentProperty GetProperty(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property identified by its alias.
|
||||
@@ -133,7 +133,7 @@ namespace Umbraco.Core.Models
|
||||
/// return the first property that was found with the alias but had no value (ie <c>HasValue</c> is <c>false</c>).</para>
|
||||
/// <para>The alias is case-insensitive.</para>
|
||||
/// </remarks>
|
||||
IPublishedProperty GetProperty(string alias, bool recurse);
|
||||
IPublishedContentProperty GetProperty(string alias, bool recurse);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a property identified by its alias.
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Represents a property of an <c>IPublishedContent</c>.
|
||||
/// </summary>
|
||||
public interface IPublishedProperty
|
||||
public interface IPublishedContentProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the alias of the property.
|
||||
@@ -14,66 +14,105 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class Member : ContentBase, IMember
|
||||
{
|
||||
private readonly IMemberType _contentType;
|
||||
private string _contentTypeAlias;
|
||||
private IMemberType _contentType;
|
||||
private readonly string _contentTypeAlias;
|
||||
private string _username;
|
||||
private string _email;
|
||||
private string _password;
|
||||
private string _rawPasswordValue;
|
||||
private object _providerUserKey;
|
||||
private Type _userTypeKey;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating an empty Member object
|
||||
/// </summary>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Member(IMemberType contentType)
|
||||
: base("", -1, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentTypeAlias = contentType.Alias;
|
||||
_contentType = contentType;
|
||||
IsApproved = true;
|
||||
|
||||
//this cannot be null but can be empty
|
||||
_rawPasswordValue = "";
|
||||
_email = "";
|
||||
_username = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Member object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Member(string name, IMemberType contentType)
|
||||
: this(contentType)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
Mandate.ParameterNotNullOrEmpty(name, "name");
|
||||
|
||||
_contentTypeAlias = contentType.Alias;
|
||||
_contentType = contentType;
|
||||
IsApproved = true;
|
||||
|
||||
//this cannot be null but can be empty
|
||||
_rawPasswordValue = "";
|
||||
_email = "";
|
||||
_username = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Member object
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="contentType"></param>
|
||||
public Member(string name, string email, string username, IMemberType contentType)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
_contentType = contentType;
|
||||
IsApproved = true;
|
||||
}
|
||||
|
||||
//TODO: Should we just get rid of this one? no reason to have a level set.
|
||||
internal Member(string name, string email, string username, string password, int parentId, IMemberType contentType)
|
||||
: base(name, parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
Mandate.ParameterNotNullOrEmpty(name, "name");
|
||||
Mandate.ParameterNotNullOrEmpty(email, "email");
|
||||
Mandate.ParameterNotNullOrEmpty(username, "username");
|
||||
|
||||
_contentTypeAlias = contentType.Alias;
|
||||
_contentType = contentType;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_password = password;
|
||||
IsApproved = true;
|
||||
|
||||
//this cannot be null but can be empty
|
||||
_rawPasswordValue = "";
|
||||
}
|
||||
|
||||
public Member(string name, string email, string username, string password, IMemberType contentType)
|
||||
: this(name, email, username, password, -1, contentType)
|
||||
/// <summary>
|
||||
/// Constructor for creating a Member object
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="rawPasswordValue">
|
||||
/// The password value passed in to this parameter should be the encoded/encrypted/hashed format of the member's password
|
||||
/// </param>
|
||||
/// <param name="contentType"></param>
|
||||
public Member(string name, string email, string username, string rawPasswordValue, IMemberType contentType)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentTypeAlias = contentType.Alias;
|
||||
_contentType = contentType;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_rawPasswordValue = rawPasswordValue;
|
||||
IsApproved = true;
|
||||
}
|
||||
|
||||
//public Member(string name, string email, string username, string password, IContentBase parent, IMemberType contentType)
|
||||
// : base(name, parent, contentType, new PropertyCollection())
|
||||
//{
|
||||
// Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
// _contentType = contentType;
|
||||
// _email = email;
|
||||
// _username = username;
|
||||
// _password = password;
|
||||
//}
|
||||
|
||||
private static readonly PropertyInfo DefaultContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.ContentTypeAlias);
|
||||
private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Username);
|
||||
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Email);
|
||||
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Password);
|
||||
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.RawPasswordValue);
|
||||
private static readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo<Member, object>(x => x.ProviderUserKey);
|
||||
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<Member, Type>(x => x.ProviderUserKeyType);
|
||||
|
||||
@@ -112,19 +151,19 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Password
|
||||
/// Gets or sets the raw password value
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Password
|
||||
[IgnoreDataMember]
|
||||
public string RawPasswordValue
|
||||
{
|
||||
get { return _password; }
|
||||
get { return _rawPasswordValue; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_password = value;
|
||||
return _password;
|
||||
}, _password, PasswordSelector);
|
||||
_rawPasswordValue = value;
|
||||
return _rawPasswordValue;
|
||||
}, _rawPasswordValue, PasswordSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +180,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoPasswordRetrievalQuestionPropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public string PasswordQuestion
|
||||
{
|
||||
get
|
||||
@@ -164,14 +203,16 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Password Answer
|
||||
/// Gets or sets the raw password answer value
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For security reasons this value should be encrypted, the encryption process is handled by the memberhip provider
|
||||
///
|
||||
/// Alias: umbracoPasswordRetrievalAnswerPropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
public string PasswordAnswer
|
||||
public string RawPasswordAnswerValue
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -199,7 +240,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoCommentPropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public string Comments
|
||||
{
|
||||
get
|
||||
@@ -228,7 +269,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoApprovePropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public bool IsApproved
|
||||
{
|
||||
get
|
||||
@@ -263,7 +304,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoLockPropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public bool IsLockedOut
|
||||
{
|
||||
get
|
||||
@@ -295,7 +336,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoLastLoginPropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public DateTime LastLoginDate
|
||||
{
|
||||
get
|
||||
@@ -327,7 +368,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoMemberLastPasswordChange
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public DateTime LastPasswordChangeDate
|
||||
{
|
||||
get
|
||||
@@ -359,7 +400,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoMemberLastLockout
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public DateTime LastLockoutDate
|
||||
{
|
||||
get
|
||||
@@ -392,7 +433,7 @@ namespace Umbraco.Core.Models
|
||||
/// Alias: umbracoFailedPasswordAttemptsPropertyTypeAlias
|
||||
/// Part of the standard properties collection.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DataMember]
|
||||
public int FailedPasswordAttempts
|
||||
{
|
||||
get
|
||||
@@ -424,14 +465,6 @@ namespace Umbraco.Core.Models
|
||||
public virtual string ContentTypeAlias
|
||||
{
|
||||
get { return _contentTypeAlias; }
|
||||
internal set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_contentTypeAlias = value;
|
||||
return _contentTypeAlias;
|
||||
}, _contentTypeAlias, DefaultContentTypeAliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -521,11 +554,17 @@ namespace Umbraco.Core.Models
|
||||
/* Internal experiment - only used for mapping queries.
|
||||
* Adding these to have first level properties instead of the Properties collection.
|
||||
*/
|
||||
[IgnoreDataMember]
|
||||
internal string LongStringPropertyValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
internal string ShortStringPropertyValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
internal int IntegerropertyValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
internal bool BoolPropertyValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
internal DateTime DateTimePropertyValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
internal string PropertyTypeAlias { get; set; }
|
||||
|
||||
private Attempt<T> WarnIfPropertyTypeNotFoundOnGet<T>(string propertyAlias, string propertyName, T defaultVal)
|
||||
@@ -595,5 +634,17 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Member)base.DeepClone();
|
||||
|
||||
//need to manually clone this since it's not settable
|
||||
clone._contentType = (IMemberType)ContentType.DeepClone();
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value == "_umbracoSystemDefaultProtectType" ? value : value.ToSafeAlias();
|
||||
_alias = value == "_umbracoSystemDefaultProtectType"
|
||||
? value
|
||||
: (value == null ? string.Empty : value.ToSafeAlias() );
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,19 @@ namespace Umbraco.Core.Models.Membership
|
||||
object ProviderUserKey { get; set; }
|
||||
string Username { get; set; }
|
||||
string Email { get; set; }
|
||||
string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the raw password value
|
||||
/// </summary>
|
||||
string RawPasswordValue { get; set; }
|
||||
|
||||
string PasswordQuestion { get; set; }
|
||||
string PasswordAnswer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the raw password answer value
|
||||
/// </summary>
|
||||
string RawPasswordAnswerValue { get; set; }
|
||||
|
||||
string Comments { get; set; }
|
||||
bool IsApproved { get; set; }
|
||||
bool IsLockedOut { get; set; }
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Services
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// The types of members to count
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System.Web.Security;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
internal static class MembershipExtensions
|
||||
internal static class MembershipUserExtensions
|
||||
{
|
||||
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName)
|
||||
{
|
||||
@@ -7,7 +7,7 @@ using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
@@ -20,13 +20,14 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class User : TracksChangesEntityBase, IUser
|
||||
public class User : Entity, IUser
|
||||
{
|
||||
public User(IUserType userType)
|
||||
{
|
||||
if (userType == null) throw new ArgumentNullException("userType");
|
||||
|
||||
_userType = userType;
|
||||
_defaultPermissions = _userType.Permissions;
|
||||
//Groups = new List<object> { userType };
|
||||
SessionTimeout = 60;
|
||||
_sectionCollection = new ObservableCollection<string>();
|
||||
@@ -38,15 +39,17 @@ namespace Umbraco.Core.Models.Membership
|
||||
_isLockedOut = false;
|
||||
_startContentId = -1;
|
||||
_startMediaId = -1;
|
||||
//cannot be null
|
||||
_rawPasswordValue = "";
|
||||
}
|
||||
|
||||
public User(string name, string email, string username, string password, IUserType userType)
|
||||
public User(string name, string email, string username, string rawPasswordValue, IUserType userType)
|
||||
: this(userType)
|
||||
{
|
||||
_name = name;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_rawPasswordValue = rawPasswordValue;
|
||||
_isApproved = true;
|
||||
_isLockedOut = false;
|
||||
_startContentId = -1;
|
||||
@@ -54,8 +57,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
}
|
||||
|
||||
private IUserType _userType;
|
||||
private bool _hasIdentity;
|
||||
private int _id;
|
||||
private string _name;
|
||||
private Type _userTypeKey;
|
||||
private readonly List<string> _addedSections;
|
||||
@@ -67,7 +68,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
|
||||
private string _username;
|
||||
private string _email;
|
||||
private string _password;
|
||||
private string _rawPasswordValue;
|
||||
private bool _isApproved;
|
||||
private bool _isLockedOut;
|
||||
private string _language;
|
||||
@@ -78,64 +79,19 @@ namespace Umbraco.Core.Models.Membership
|
||||
private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartContentId);
|
||||
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
|
||||
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
|
||||
private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo<User, object>(x => x.Id);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
|
||||
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<User, Type>(x => x.ProviderUserKeyType);
|
||||
|
||||
private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Username);
|
||||
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Email);
|
||||
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Password);
|
||||
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.RawPasswordValue);
|
||||
private static readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsLockedOut);
|
||||
private static readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsApproved);
|
||||
private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
|
||||
private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.DefaultPermissions);
|
||||
private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
|
||||
private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.HasIdentity);
|
||||
private static readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
|
||||
|
||||
#region Implementation of IEntity
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool HasIdentity
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hasIdentity;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_hasIdentity = value;
|
||||
return _hasIdentity;
|
||||
}, _hasIdentity, HasIdentitySelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_id = value;
|
||||
HasIdentity = true; //set the has Identity
|
||||
return _id;
|
||||
}, _id, IdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
//this doesn't get used
|
||||
[IgnoreDataMember]
|
||||
public Guid Key { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Implementation of IMembershipUser
|
||||
|
||||
[IgnoreDataMember]
|
||||
@@ -204,16 +160,16 @@ namespace Umbraco.Core.Models.Membership
|
||||
}
|
||||
}
|
||||
[DataMember]
|
||||
public string Password
|
||||
public string RawPasswordValue
|
||||
{
|
||||
get { return _password; }
|
||||
get { return _rawPasswordValue; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_password = value;
|
||||
return _password;
|
||||
}, _password, PasswordSelector);
|
||||
_rawPasswordValue = value;
|
||||
return _rawPasswordValue;
|
||||
}, _rawPasswordValue, PasswordSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,13 +207,9 @@ namespace Umbraco.Core.Models.Membership
|
||||
[IgnoreDataMember]
|
||||
public string PasswordQuestion { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string PasswordAnswer { get; set; }
|
||||
public string RawPasswordAnswerValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string Comments { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime CreateDate { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
public string Comments { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastLoginDate { get; set; }
|
||||
[IgnoreDataMember]
|
||||
@@ -488,7 +440,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
_removedSections.Add(e.OldItems.Cast<string>().First());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal class used to wrap the user in a profile
|
||||
/// </summary>
|
||||
@@ -512,6 +464,24 @@ namespace Umbraco.Core.Models.Membership
|
||||
get { return _user.Name; }
|
||||
set { _user.Name = value; }
|
||||
}
|
||||
|
||||
protected bool Equals(UserProfile other)
|
||||
{
|
||||
return _user.Equals(other._user);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UserProfile) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _user.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
/// <summary>
|
||||
/// The value stored for the pre-value field
|
||||
/// </summary>
|
||||
public string Value { get; private set; }
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The database id for the pre-value field value
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class Property : Entity
|
||||
{
|
||||
private readonly PropertyType _propertyType;
|
||||
private PropertyType _propertyType;
|
||||
private Guid _version;
|
||||
private object _value;
|
||||
|
||||
@@ -147,5 +147,16 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
return _propertyType.IsPropertyValueValid(value);
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Property)base.DeepClone();
|
||||
|
||||
//need to manually assign since this is a readonly property
|
||||
clone._propertyType = (PropertyType)PropertyType.DeepClone();
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -13,7 +14,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged
|
||||
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
|
||||
{
|
||||
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
|
||||
internal Action OnAdd;
|
||||
@@ -195,5 +196,19 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a deep clone of this property collection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object DeepClone()
|
||||
{
|
||||
var newList = new PropertyCollection();
|
||||
foreach (var p in this)
|
||||
{
|
||||
newList.Add((Property)p.DeepClone());
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,42 +22,10 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Xml of the property and its value</returns>
|
||||
public static XElement ToXml(this Property property)
|
||||
{
|
||||
return property.ToXml(ApplicationContext.Current.Services.DataTypeService);
|
||||
var xmlSerializer = new EntityXmlSerializer();
|
||||
return xmlSerializer.Serialize(ApplicationContext.Current.Services.DataTypeService, property);
|
||||
}
|
||||
|
||||
internal static XElement ToXml(this Property property, IDataTypeService dataTypeService)
|
||||
{
|
||||
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "data" : property.Alias.ToSafeAlias();
|
||||
|
||||
var xd = new XmlDocument();
|
||||
var xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
|
||||
|
||||
//Add the property alias to the legacy schema
|
||||
if (UmbracoSettings.UseLegacyXmlSchema)
|
||||
{
|
||||
var alias = xd.CreateAttribute("alias");
|
||||
alias.Value = property.Alias.ToSafeAlias();
|
||||
xmlNode.Attributes.Append(alias);
|
||||
}
|
||||
|
||||
//This seems to fail during testing
|
||||
//SD: With the new null checks below, this shouldn't fail anymore.
|
||||
var dt = property.PropertyType.DataType(property.Id, dataTypeService);
|
||||
if (dt != null && dt.Data != null)
|
||||
{
|
||||
//We've already got the value for the property so we're going to give it to the
|
||||
// data type's data property so it doesn't go re-look up the value from the db again.
|
||||
var defaultData = dt.Data as IDataValueSetter;
|
||||
if (defaultData != null)
|
||||
{
|
||||
defaultData.SetValue(property.Value, property.PropertyType.DataTypeDatabaseType.ToString());
|
||||
}
|
||||
|
||||
xmlNode.AppendChild(dt.Data.ToXMl(xd));
|
||||
}
|
||||
|
||||
var element = xmlNode.GetXElement();
|
||||
return element;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -107,23 +107,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
internal PropertyGroup Clone()
|
||||
{
|
||||
var clone = (PropertyGroup) this.MemberwiseClone();
|
||||
var collection = new PropertyTypeCollection();
|
||||
foreach (var propertyType in this.PropertyTypes)
|
||||
{
|
||||
var property = propertyType.Clone();
|
||||
property.ResetIdentity();
|
||||
property.ResetDirtyProperties(false);
|
||||
collection.Add(property);
|
||||
}
|
||||
clone.PropertyTypes = collection;
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ParentId from the lazy integer id
|
||||
/// </summary>
|
||||
@@ -157,5 +140,6 @@ namespace Umbraco.Core.Models
|
||||
//Calculate the hash code for the product.
|
||||
return hashName ^ hashId;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -13,9 +14,10 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract]
|
||||
public class PropertyGroupCollection : KeyedCollection<string, PropertyGroup>, INotifyCollectionChanged
|
||||
public class PropertyGroupCollection : KeyedCollection<string, PropertyGroup>, INotifyCollectionChanged, IDeepCloneable
|
||||
{
|
||||
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
|
||||
|
||||
internal Action OnAdd;
|
||||
|
||||
internal PropertyGroupCollection()
|
||||
@@ -131,5 +133,15 @@ namespace Umbraco.Core.Models
|
||||
CollectionChanged(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
var newGroup = new PropertyGroupCollection();
|
||||
foreach (var p in this)
|
||||
{
|
||||
newGroup.Add((PropertyGroup)p.DeepClone());
|
||||
}
|
||||
return newGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -94,7 +95,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
_alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
@@ -388,7 +389,9 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//TODO: We must ensure that the property value can actually be saved based on the specified database type
|
||||
|
||||
//TODO Add PropertyEditor validation when its relevant to introduce
|
||||
/*if (value is IEditorModel && DataTypeControlId != Guid.Empty)
|
||||
{
|
||||
@@ -402,14 +405,6 @@ namespace Umbraco.Core.Models
|
||||
return true;
|
||||
}
|
||||
|
||||
internal PropertyType Clone()
|
||||
{
|
||||
var clone = (PropertyType) this.MemberwiseClone();
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public bool Equals(PropertyType other)
|
||||
{
|
||||
//Check whether the compared object is null.
|
||||
@@ -433,5 +428,20 @@ namespace Umbraco.Core.Models
|
||||
//Calculate the hash code for the product.
|
||||
return hashName ^ hashAlias;
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (PropertyType)base.DeepClone();
|
||||
|
||||
//need to manually assign the Lazy value as it will not be automatically mapped
|
||||
if (PropertyGroupId != null)
|
||||
{
|
||||
clone._propertyGroupId = new Lazy<int>(() => PropertyGroupId.Value);
|
||||
}
|
||||
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -13,9 +14,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract]
|
||||
public class PropertyTypeCollection : KeyedCollection<string, PropertyType>, INotifyCollectionChanged
|
||||
public class PropertyTypeCollection : KeyedCollection<string, PropertyType>, INotifyCollectionChanged, IDeepCloneable
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
|
||||
|
||||
[IgnoreDataMember]
|
||||
internal Action OnAdd;
|
||||
|
||||
internal PropertyTypeCollection()
|
||||
@@ -131,5 +135,15 @@ namespace Umbraco.Core.Models
|
||||
CollectionChanged(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
var newGroup = new PropertyTypeCollection();
|
||||
foreach (var p in this)
|
||||
{
|
||||
newGroup.Add((PropertyType)p.DeepClone());
|
||||
}
|
||||
return newGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// Adds a property to the extended content.
|
||||
/// </summary>
|
||||
/// <param name="property">The property to add.</param>
|
||||
void AddProperty(IPublishedProperty property);
|
||||
void AddProperty(IPublishedContentProperty property);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether properties were added to the extended content.
|
||||
|
||||
@@ -66,10 +66,10 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
#region IPublishedContentExtended
|
||||
|
||||
void IPublishedContentExtended.AddProperty(IPublishedProperty property)
|
||||
void IPublishedContentExtended.AddProperty(IPublishedContentProperty property)
|
||||
{
|
||||
if (_properties == null)
|
||||
_properties = new Collection<IPublishedProperty>();
|
||||
_properties = new Collection<IPublishedContentProperty>();
|
||||
_properties.Add(property);
|
||||
}
|
||||
|
||||
@@ -113,9 +113,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
#region Properties
|
||||
|
||||
private ICollection<IPublishedProperty> _properties;
|
||||
private ICollection<IPublishedContentProperty> _properties;
|
||||
|
||||
public override ICollection<IPublishedProperty> Properties
|
||||
public override ICollection<IPublishedContentProperty> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -138,7 +138,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
}
|
||||
|
||||
public override IPublishedProperty GetProperty(string alias)
|
||||
public override IPublishedContentProperty GetProperty(string alias)
|
||||
{
|
||||
return _properties == null
|
||||
? Content.GetProperty(alias)
|
||||
|
||||
@@ -141,9 +141,21 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
if (GetPublishedContentTypeCallback != null)
|
||||
return GetPublishedContentTypeCallback(alias);
|
||||
|
||||
var contentType = itemType == PublishedItemType.Content
|
||||
? (IContentTypeComposition)ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias)
|
||||
: (IContentTypeComposition)ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias);
|
||||
IContentTypeComposition contentType;
|
||||
switch (itemType)
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
contentType = ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias);
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
contentType = ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias);
|
||||
break;
|
||||
case PublishedItemType.Member:
|
||||
contentType = ApplicationContext.Current.Services.MemberTypeService.Get(alias);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("itemType");
|
||||
}
|
||||
|
||||
if (contentType == null)
|
||||
throw new Exception(string.Format("ContentTypeService failed to find a {0} type with alias \"{1}\".",
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
#region Properties
|
||||
|
||||
public virtual ICollection<IPublishedProperty> Properties
|
||||
public virtual ICollection<IPublishedContentProperty> Properties
|
||||
{
|
||||
get { return Content.Properties; }
|
||||
}
|
||||
@@ -193,12 +193,12 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
get { return Content[alias]; }
|
||||
}
|
||||
|
||||
public virtual IPublishedProperty GetProperty(string alias)
|
||||
public virtual IPublishedContentProperty GetProperty(string alias)
|
||||
{
|
||||
return Content.GetProperty(alias);
|
||||
}
|
||||
|
||||
public virtual IPublishedProperty GetProperty(string alias, bool recurse)
|
||||
public virtual IPublishedContentProperty GetProperty(string alias, bool recurse)
|
||||
{
|
||||
return Content.GetProperty(alias, recurse);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// Provides a base class for <c>IPublishedProperty</c> implementations which converts and caches
|
||||
/// the value source to the actual value to use when rendering content.
|
||||
/// </summary>
|
||||
internal abstract class PublishedPropertyBase : IPublishedProperty
|
||||
internal abstract class PublishedPropertyBase : IPublishedContentProperty
|
||||
{
|
||||
public readonly PublishedPropertyType PropertyType;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IPublishedProperty"/> type.
|
||||
/// Represents an <see cref="IPublishedContentProperty"/> type.
|
||||
/// </summary>
|
||||
/// <remarks>Instances of the <see cref="PublishedPropertyType"/> class are immutable, ie
|
||||
/// if the property type changes, then a new class needs to be created.</remarks>
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// A media.
|
||||
/// </summary>
|
||||
Media
|
||||
Media,
|
||||
|
||||
/// <summary>
|
||||
/// A member.
|
||||
/// </summary>
|
||||
Member
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
internal class PreviewXmlDto
|
||||
{
|
||||
[Column("nodeId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "", OnColumns = "nodeId, versionId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsContentPreviewXml", OnColumns = "nodeId, versionId")]
|
||||
[ForeignKey(typeof(ContentDto), Column = "nodeId")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
internal class UserLoginDto
|
||||
{
|
||||
[Column("contextID")]
|
||||
[Index(IndexTypes.Clustered, Name = "umbracoUserLogins_Index")]
|
||||
[Index(IndexTypes.Clustered, Name = "IX_umbracoUserLogins_Index")]
|
||||
public Guid ContextId { get; set; }
|
||||
|
||||
[Column("userID")]
|
||||
|
||||
@@ -107,5 +107,6 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get { return _relationType.Id; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,18 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public RelationType(Guid childObjectType, Guid parentObjectType, string @alias)
|
||||
{
|
||||
Mandate.ParameterNotNullOrEmpty(@alias, "alias");
|
||||
_childObjectType = childObjectType;
|
||||
_parentObjectType = parentObjectType;
|
||||
_alias = alias;
|
||||
Name = _alias;
|
||||
}
|
||||
|
||||
public RelationType(Guid childObjectType, Guid parentObjectType, string @alias, string name)
|
||||
:this(childObjectType, parentObjectType, @alias)
|
||||
{
|
||||
Mandate.ParameterNotNullOrEmpty(name, "name");
|
||||
Name = name;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<RelationType, string>(x => x.Name);
|
||||
@@ -118,5 +127,6 @@ namespace Umbraco.Core.Models
|
||||
}, _childObjectType, ChildObjectTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
@@ -34,7 +35,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
UpdateDate = updateDate;
|
||||
CreateDate = createDate;
|
||||
Key = Id.ToString().EncodeAsGuid();
|
||||
Key = Id.ToString(CultureInfo.InvariantCulture).EncodeAsGuid();
|
||||
Id = id;
|
||||
ServerAddress = serverAddress;
|
||||
ComputerName = computerName;
|
||||
@@ -51,7 +52,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
CreateDate = createDate;
|
||||
UpdateDate = createDate;
|
||||
Key = 0.ToString().EncodeAsGuid();
|
||||
Key = 0.ToString(CultureInfo.InvariantCulture).EncodeAsGuid();
|
||||
ServerAddress = serverAddress;
|
||||
ComputerName = computerName;
|
||||
}
|
||||
|
||||
@@ -132,5 +132,6 @@ namespace Umbraco.Core.Models
|
||||
}, _comment, CommentSelector);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -14,20 +16,18 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class Template : File, ITemplate
|
||||
{
|
||||
private readonly string _alias;
|
||||
private readonly string _name;
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private int _creatorId;
|
||||
private int _level;
|
||||
private int _sortOrder;
|
||||
private int _parentId;
|
||||
private int _masterTemplateId;
|
||||
private string _masterTemplateAlias;
|
||||
|
||||
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.CreatorId);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.Level);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.ParentId);
|
||||
//private static readonly PropertyInfo MasterTemplateIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.MasterTemplateId);
|
||||
private static readonly PropertyInfo MasterTemplateAliasSelector = ExpressionHelper.GetPropertyInfo<Template, string>(x => x.MasterTemplateAlias);
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
base.Path = path;
|
||||
ParentId = -1;
|
||||
_name = name.Replace("/", ".").Replace("\\", "");
|
||||
_alias = alias.ToSafeAlias();
|
||||
_name = name; //.Replace("/", ".").Replace("\\", ""); // why? that's just the name!
|
||||
_alias = alias.ToCleanString(CleanStringType.UnderscoreAlias);
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
@@ -197,5 +197,18 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
MasterTemplateId = new Lazy<int>(() => masterTemplate.Id);
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Template)base.DeepClone();
|
||||
|
||||
//need to manually assign since they are readonly properties
|
||||
clone._alias = Alias;
|
||||
clone._name = Name;
|
||||
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -46,11 +47,13 @@ namespace Umbraco.Core.Models
|
||||
public UmbracoEntity()
|
||||
{
|
||||
AdditionalData = new Dictionary<string, object>();
|
||||
UmbracoProperties = new List<UmbracoProperty>();
|
||||
}
|
||||
|
||||
public UmbracoEntity(bool trashed)
|
||||
{
|
||||
AdditionalData = new Dictionary<string, object>();
|
||||
UmbracoProperties = new List<UmbracoProperty>();
|
||||
Trashed = trashed;
|
||||
}
|
||||
|
||||
@@ -58,6 +61,7 @@ namespace Umbraco.Core.Models
|
||||
public UmbracoEntity(UInt64 trashed)
|
||||
{
|
||||
AdditionalData = new Dictionary<string, object>();
|
||||
UmbracoProperties = new List<UmbracoProperty>();
|
||||
Trashed = trashed == 1;
|
||||
}
|
||||
|
||||
@@ -287,11 +291,39 @@ namespace Umbraco.Core.Models
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
public IList<UmbracoProperty> UmbracoProperties { get; set; }
|
||||
|
||||
internal class UmbracoProperty
|
||||
|
||||
internal class UmbracoProperty : IDeepCloneable
|
||||
{
|
||||
public Guid DataTypeControlId { get; set; }
|
||||
public string Value { get; set; }
|
||||
public object DeepClone()
|
||||
{
|
||||
//Memberwise clone on Entity will work since it doesn't have any deep elements
|
||||
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
|
||||
var clone = MemberwiseClone();
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected bool Equals(UmbracoProperty other)
|
||||
{
|
||||
return DataTypeControlId.Equals(other.DataTypeControlId) && string.Equals(Value, other.Value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UmbracoProperty) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (DataTypeControlId.GetHashCode()*397) ^ (Value != null ? Value.GetHashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
@@ -8,7 +9,10 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// A resolver to return all IApplicationEvents objects
|
||||
/// </summary>
|
||||
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationEventHandler>
|
||||
/// <remarks>
|
||||
/// This is disposable because after the app has started it should be disposed to release any memory being occupied by instances.
|
||||
/// </remarks>
|
||||
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationEventHandler>, IDisposable
|
||||
{
|
||||
|
||||
private readonly LegacyStartupHandlerResolver _legacyResolver;
|
||||
@@ -53,7 +57,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
|
||||
protected override bool SupportsClear
|
||||
{
|
||||
get { return false; }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override bool SupportsInsert
|
||||
@@ -61,7 +65,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
|
||||
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>, IDisposable
|
||||
{
|
||||
internal LegacyStartupHandlerResolver(IEnumerable<Type> legacyStartupHandlers)
|
||||
: base(legacyStartupHandlers)
|
||||
@@ -73,7 +77,72 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
get { return Values; }
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ResetCollections();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is disposed.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get { return _disposed; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
// Use SupressFinalize in case a subclass of this type implements a finalizer.
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~ApplicationEventsResolver()
|
||||
{
|
||||
// Run dispose but let the class know it was due to the finalizer running.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
// Only operate if we haven't already disposed
|
||||
if (IsDisposed || disposing == false) return;
|
||||
|
||||
using (new WriteLock(_disposalLocker))
|
||||
{
|
||||
// Check again now we're inside the lock
|
||||
if (IsDisposed) return;
|
||||
|
||||
// Call to actually release resources. This method is only
|
||||
// kept separate so that the entire disposal logic can be used as a VS snippet
|
||||
DisposeResources();
|
||||
|
||||
// Indicate that the instance has been disposed.
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear out all of the instances, we don't want them hanging around and cluttering up memory
|
||||
/// </summary>
|
||||
private void DisposeResources()
|
||||
{
|
||||
_legacyResolver.Dispose();
|
||||
ResetCollections();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the list of types.
|
||||
/// Clears the list of types
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support clearing types.</exception>
|
||||
public virtual void Clear()
|
||||
@@ -336,6 +336,20 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WARNING! Do not use this unless you know what you are doing, clear all types registered and instances
|
||||
/// created. Typically only used if a resolver is no longer used in an application and memory is to be GC'd
|
||||
/// </summary>
|
||||
internal void ResetCollections()
|
||||
{
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
_instanceTypes.Clear();
|
||||
_sortedValues = null;
|
||||
_applicationInstances = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the specified index.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Xml;
|
||||
|
||||
namespace Umbraco.Core.Packaging.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class InstallAction
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
|
||||
public string PackageName { get; set; }
|
||||
|
||||
public string RunAt { get; set; }//NOTE Should this default to "install"
|
||||
|
||||
public bool Undo { get; set; }
|
||||
|
||||
public XmlNode XmlData { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Packaging.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class InstallationSummary
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public IEnumerable<int> DataTypesInstalled { get; set; }
|
||||
public IEnumerable<int> LanguagesInstalled { get; set; }
|
||||
public IEnumerable<int> DictionaryItemsInstalled { get; set; }
|
||||
public IEnumerable<int> MacrosInstalled { get; set; }
|
||||
public IEnumerable<KeyValuePair<string, bool>> FilesInstalled { get; set;}
|
||||
public IEnumerable<int> TemplatesInstalled { get; set; }
|
||||
public IEnumerable<int> DocumentTypesInstalled { get; set; }
|
||||
public IEnumerable<int> StylesheetsInstalled { get; set; }
|
||||
public IEnumerable<int> DocumentsInstalled { get; set; }
|
||||
public IEnumerable<InstallAction> InstallActions { get; set; }
|
||||
public IEnumerable<UninstallAction> UninstallActions { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Packaging.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class MetaData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Version { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string License { get; set; }
|
||||
public string LicenseUrl { get; set; }
|
||||
public int ReqMajor { get; set; }
|
||||
public int ReqMinor { get; set; }
|
||||
public int ReqPatch { get; set; }
|
||||
public string AuthorName { get; set; }
|
||||
public string AuthorUrl { get; set; }
|
||||
public string Readme { get; set; }
|
||||
public string Control { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Xml;
|
||||
|
||||
namespace Umbraco.Core.Packaging.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class UninstallAction
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
|
||||
public string PackageName { get; set; }
|
||||
|
||||
public string RunAt { get; set; }//NOTE Should this default to "install"
|
||||
|
||||
public bool Undo { get; set; }//NOTE: Should thid default to "False"?
|
||||
|
||||
public XmlNode XmlData { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Packaging
|
||||
{
|
||||
internal interface IPackageBuilding
|
||||
{
|
||||
}
|
||||
|
||||
internal class PackageBuilding : IPackageBuilding
|
||||
{
|
||||
private readonly PackagingService _packagingService;
|
||||
|
||||
public PackageBuilding(PackagingService packagingService)
|
||||
{
|
||||
_packagingService = packagingService;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Packaging
|
||||
{
|
||||
internal interface IPackageExtraction
|
||||
{
|
||||
bool Extract(string packageFilePath, string destinationFolder);
|
||||
string ExtractToTemporaryFolder(string packageFilePath);
|
||||
string GetPackageConfigFromArchive(string packageFilePath, string fileToRead = "package.xml");
|
||||
}
|
||||
|
||||
internal class PackageExtraction : IPackageExtraction
|
||||
{
|
||||
public bool Extract(string packageFilePath, string destinationFolder)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public string ExtractToTemporaryFolder(string packageFilePath)
|
||||
{
|
||||
string tempDir = Path.Combine(IOHelper.MapPath(SystemDirectories.Data), Guid.NewGuid().ToString("D"));
|
||||
Directory.CreateDirectory(tempDir);
|
||||
Extract(packageFilePath, tempDir);
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
public string GetPackageConfigFromArchive(string packageFilePath, string fileToRead = "package.xml")
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Packaging
|
||||
{
|
||||
internal interface IPackageInstallation
|
||||
{
|
||||
InstallationSummary InstallPackage(string packageFilePath, int userId = 0);
|
||||
MetaData GetPackageMetaData(string packageFilePath);
|
||||
}
|
||||
|
||||
internal class PackageInstallation : IPackageInstallation
|
||||
{
|
||||
private readonly PackagingService _packagingService;
|
||||
private readonly PackageExtraction _packageExtraction;
|
||||
|
||||
public PackageInstallation(PackagingService packagingService, PackageExtraction packageExtraction)
|
||||
{
|
||||
_packagingService = packagingService;
|
||||
_packageExtraction = packageExtraction;
|
||||
}
|
||||
|
||||
public InstallationSummary InstallPackage(string packageFilePath, int userId = 0)
|
||||
{
|
||||
var summary = new InstallationSummary();
|
||||
return summary;
|
||||
}
|
||||
|
||||
public MetaData GetPackageMetaData(string packageFilePath)
|
||||
{
|
||||
var metaData = new MetaData();
|
||||
return metaData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,10 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
var containsKey = _cache.ContainsKey(compositeKey);
|
||||
if (containsKey)
|
||||
{
|
||||
return _cache[compositeKey];
|
||||
var result = _cache[compositeKey];
|
||||
|
||||
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
|
||||
return (IEntity)result.DeepClone();
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -56,7 +59,12 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
into key
|
||||
let containsKey = _cache.ContainsKey(key)
|
||||
where containsKey
|
||||
select _cache[key]).ToList();
|
||||
select _cache[key]
|
||||
into result
|
||||
//don't return null objects
|
||||
where result != null
|
||||
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
|
||||
select (IEntity)result.DeepClone()).ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -67,7 +75,14 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IEntity> GetAllByType(Type type)
|
||||
{
|
||||
var list = _cache.Keys.Where(key => key.Contains(type.Name)).Select(key => _cache[key]).ToList();
|
||||
var list = _cache.Keys
|
||||
.Where(key => key.Contains(type.Name))
|
||||
.Select(key => _cache[key])
|
||||
//don't return null objects
|
||||
.Where(result => result != null)
|
||||
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
|
||||
.Select(result => (IEntity)result.DeepClone())
|
||||
.ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -78,6 +93,9 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
/// <param name="entity"></param>
|
||||
public void Save(Type type, IEntity entity)
|
||||
{
|
||||
//IMPORTANT: we must clone to store, see: http://issues.umbraco.org/issue/U4-4259
|
||||
entity = (IEntity)entity.DeepClone();
|
||||
|
||||
_cache.AddOrUpdate(GetCompositeId(type, entity.Id), entity, (x, y) => entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -29,6 +29,9 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
/// when there are async requests being made even in the context of a web request, the HttpContext.Current will be null but the HttpRuntime.Cache will
|
||||
/// always be available.
|
||||
///
|
||||
/// TODO: Each item that get's added to this cache will be a clone of the original with it's dirty properties reset, and every item that is resolved from the cache
|
||||
/// is a clone of the item that is in there, otherwise we end up with thread safety issues since multiple thread would be working on the exact same entity at the same time.
|
||||
///
|
||||
/// </remarks>
|
||||
internal sealed class RuntimeCacheProvider : IRepositoryCacheProvider
|
||||
{
|
||||
@@ -64,8 +67,11 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
{
|
||||
//ensure the key doesn't exist anymore in the tracker
|
||||
_keyTracker.Remove(key);
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
|
||||
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
|
||||
return (IEntity)result.DeepClone();
|
||||
}
|
||||
|
||||
public IEnumerable<IEntity> GetByIds(Type type, List<Guid> ids)
|
||||
@@ -85,7 +91,8 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
}
|
||||
else
|
||||
{
|
||||
collection.Add(result);
|
||||
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
|
||||
collection.Add((IEntity)result.DeepClone());
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
@@ -110,7 +117,8 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
}
|
||||
else
|
||||
{
|
||||
collection.Add(result);
|
||||
//IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259
|
||||
collection.Add((IEntity)result.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,6 +127,9 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
|
||||
public void Save(Type type, IEntity entity)
|
||||
{
|
||||
//IMPORTANT: we must clone to store, see: http://issues.umbraco.org/issue/U4-4259
|
||||
entity = (IEntity)entity.DeepClone();
|
||||
|
||||
var key = GetCompositeId(type, entity.Id);
|
||||
|
||||
_keyTracker.TryAdd(key);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a database index definition retreived by querying the database
|
||||
/// </summary>
|
||||
internal class DbIndexDefinition
|
||||
{
|
||||
public virtual string IndexName { get; set; }
|
||||
public virtual string TableName { get; set; }
|
||||
public virtual string ColumnName { get; set; }
|
||||
public virtual bool IsUnique { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
NodeId = entity.Id,
|
||||
Email = entity.Email,
|
||||
LoginName = entity.Username,
|
||||
Password = entity.Password,
|
||||
Password = entity.RawPasswordValue,
|
||||
ContentVersionDto = BuildDto(entity as Member)
|
||||
};
|
||||
return member;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
var properties = CreateProperties(_memberTypes[dto.ContentTypeAlias], dto.Properties, dto.CreateDate);
|
||||
|
||||
var member = new Member(dto.Text, dto.Email, dto.LoginName, dto.Password, dto.ParentId, _memberTypes[dto.ContentTypeAlias])
|
||||
var member = new Member(dto.Text, dto.Email, dto.LoginName, dto.Password, _memberTypes[dto.ContentTypeAlias])
|
||||
{
|
||||
Id = dto.NodeId,
|
||||
CreateDate = dto.CreateDate,
|
||||
@@ -33,7 +33,6 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Path = dto.Path,
|
||||
SortOrder = dto.SortOrder,
|
||||
Version = dto.VersionId,
|
||||
ContentTypeAlias = dto.ContentTypeAlias,
|
||||
Properties = new PropertyCollection(properties)
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Key = guidId,
|
||||
StartContentId = dto.ContentStartId,
|
||||
StartMediaId = dto.MediaStartId.HasValue ? dto.MediaStartId.Value : -1,
|
||||
Password = dto.Password,
|
||||
RawPasswordValue = dto.Password,
|
||||
Username = dto.Login,
|
||||
Name = dto.UserName,
|
||||
IsLockedOut = dto.NoConsole,
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Email = entity.Email,
|
||||
Login = entity.Username,
|
||||
NoConsole = entity.IsLockedOut,
|
||||
Password = entity.Password,
|
||||
Password = entity.RawPasswordValue,
|
||||
UserLanguage = entity.Language,
|
||||
UserName = entity.Name,
|
||||
Type = short.Parse(entity.UserType.Id.ToString(CultureInfo.InvariantCulture)),
|
||||
|
||||
@@ -48,12 +48,12 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
|
||||
CacheMap<Member, MemberDto>(src => src.Email, dto => dto.Email);
|
||||
CacheMap<Member, MemberDto>(src => src.Username, dto => dto.LoginName);
|
||||
CacheMap<Member, MemberDto>(src => src.Password, dto => dto.Password);
|
||||
CacheMap<Member, MemberDto>(src => src.RawPasswordValue, dto => dto.Password);
|
||||
|
||||
CacheMap<Member, PropertyDataDto>(src => src.IsApproved, dto => dto.Integer);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.IsLockedOut, dto => dto.Integer);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.Comments, dto => dto.Text);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.PasswordAnswer, dto => dto.VarChar);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.RawPasswordAnswerValue, dto => dto.VarChar);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.PasswordQuestion, dto => dto.VarChar);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.FailedPasswordAttempts, dto => dto.Integer);
|
||||
CacheMap<Member, PropertyDataDto>(src => src.LastLockoutDate, dto => dto.Date);
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<User, UserDto>(src => src.Id, dto => dto.Id);
|
||||
CacheMap<User, UserDto>(src => src.Email, dto => dto.Email);
|
||||
CacheMap<User, UserDto>(src => src.Username, dto => dto.Login);
|
||||
CacheMap<User, UserDto>(src => src.Password, dto => dto.Password);
|
||||
CacheMap<User, UserDto>(src => src.RawPasswordValue, dto => dto.Password);
|
||||
CacheMap<User, UserDto>(src => src.Name, dto => dto.UserName);
|
||||
CacheMap<User, UserDto>(src => src.DefaultPermissions, dto => dto.DefaultPermissions);
|
||||
CacheMap<User, UserDto>(src => src.StartMediaId, dto => dto.MediaStartId);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// Used if a migration has executed but the whole process has failed and cannot be rolled back
|
||||
/// </summary>
|
||||
internal class DataLossException : Exception
|
||||
{
|
||||
public DataLossException(string msg)
|
||||
: base(msg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DataLossException(string msg, Exception inner)
|
||||
: base(msg, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,67 +125,62 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
var result = new DatabaseSchemaResult();
|
||||
|
||||
//get the db index defs
|
||||
result.DbIndexDefinitions = SqlSyntaxContext.SqlSyntaxProvider.GetDefinedIndexes(_database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
|
||||
foreach (var item in OrderedTables.OrderBy(x => x.Key))
|
||||
{
|
||||
var tableDefinition = DefinitionFactory.GetTableDefinition(item.Value);
|
||||
result.TableDefinitions.Add(tableDefinition);
|
||||
}
|
||||
|
||||
//Check tables in configured database against tables in schema
|
||||
var tablesInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetTablesInSchema(_database).ToList();
|
||||
var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList();
|
||||
//Add valid and invalid table differences to the result object
|
||||
var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema);
|
||||
foreach (var tableName in validTableDifferences)
|
||||
{
|
||||
result.ValidTables.Add(tableName);
|
||||
}
|
||||
var invalidTableDifferences =
|
||||
tablesInDatabase.Except(tablesInSchema)
|
||||
.Union(tablesInSchema.Except(tablesInDatabase));
|
||||
foreach (var tableName in invalidTableDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Table", tableName));
|
||||
}
|
||||
ValidateDbTables(result);
|
||||
|
||||
//Check columns in configured database against columns in schema
|
||||
var columnsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(_database);
|
||||
var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList();
|
||||
var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList();
|
||||
//Add valid and invalid column differences to the result object
|
||||
var validColumnDifferences = columnsPerTableInDatabase.Intersect(columnsPerTableInSchema);
|
||||
foreach (var column in validColumnDifferences)
|
||||
{
|
||||
result.ValidColumns.Add(column);
|
||||
}
|
||||
var invalidColumnDifferences = columnsPerTableInDatabase.Except(columnsPerTableInSchema);
|
||||
foreach (var column in invalidColumnDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Column", column));
|
||||
}
|
||||
ValidateDbColumns(result);
|
||||
|
||||
ValidateDbIndexes(result);
|
||||
|
||||
ValidateDbConstraints(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ValidateDbConstraints(DatabaseSchemaResult result)
|
||||
{
|
||||
//MySql doesn't conform to the "normal" naming of constraints, so there is currently no point in doing these checks.
|
||||
//NOTE: At a later point we do other checks for MySql, but ideally it should be necessary to do special checks for different providers.
|
||||
//TODO: At a later point we do other checks for MySql, but ideally it should be necessary to do special checks for different providers.
|
||||
// ALso note that to get the constraints for MySql we have to open a connection which we currently have not.
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider)
|
||||
return result;
|
||||
return;
|
||||
|
||||
//Check constraints in configured database against constraints in schema
|
||||
var constraintsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList();
|
||||
var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("FK_")).Select(x => x.Item3).ToList();
|
||||
var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("PK_")).Select(x => x.Item3).ToList();
|
||||
var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("IX_")).Select(x => x.Item3).ToList();
|
||||
var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("FK_")).Select(x => x.Item3).ToList();
|
||||
var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("PK_")).Select(x => x.Item3).ToList();
|
||||
var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("IX_")).Select(x => x.Item3).ToList();
|
||||
var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList();
|
||||
var unknownConstraintsInDatabase =
|
||||
constraintsInDatabase.Where(
|
||||
x =>
|
||||
x.Item3.StartsWith("FK_") == false && x.Item3.StartsWith("PK_") == false &&
|
||||
x.Item3.StartsWith("IX_") == false).Select(x => x.Item3).ToList();
|
||||
x.Item3.InvariantStartsWith("FK_") == false && x.Item3.InvariantStartsWith("PK_") == false &&
|
||||
x.Item3.InvariantStartsWith("IX_") == false).Select(x => x.Item3).ToList();
|
||||
var foreignKeysInSchema = result.TableDefinitions.SelectMany(x => x.ForeignKeys.Select(y => y.Name)).ToList();
|
||||
var primaryKeysInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => y.PrimaryKeyName)).ToList();
|
||||
var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList();
|
||||
var primaryKeysInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => y.PrimaryKeyName))
|
||||
.Where(x => x.IsNullOrWhiteSpace() == false).ToList();
|
||||
|
||||
//Add valid and invalid foreign key differences to the result object
|
||||
// We'll need to do invariant contains with case insensitivity because foreign key, primary key, and even index naming w/ MySQL is not standardized
|
||||
// In theory you could have: FK_ or fk_ ...or really any standard that your development department (or developer) chooses to use.
|
||||
foreach (var unknown in unknownConstraintsInDatabase)
|
||||
{
|
||||
if (foreignKeysInSchema.Contains(unknown) || primaryKeysInSchema.Contains(unknown) || indexesInSchema.Contains(unknown))
|
||||
if (foreignKeysInSchema.InvariantContains(unknown) || primaryKeysInSchema.InvariantContains(unknown) || indexesInSchema.InvariantContains(unknown))
|
||||
{
|
||||
result.ValidConstraints.Add(unknown);
|
||||
}
|
||||
@@ -194,40 +189,122 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
result.Errors.Add(new Tuple<string, string>("Unknown", unknown));
|
||||
}
|
||||
}
|
||||
var validForeignKeyDifferences = foreignKeysInDatabase.Intersect(foreignKeysInSchema);
|
||||
|
||||
//Foreign keys:
|
||||
|
||||
var validForeignKeyDifferences = foreignKeysInDatabase.Intersect(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var foreignKey in validForeignKeyDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(foreignKey);
|
||||
}
|
||||
var invalidForeignKeyDifferences = foreignKeysInDatabase.Except(foreignKeysInSchema);
|
||||
var invalidForeignKeyDifferences =
|
||||
foreignKeysInDatabase.Except(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Union(foreignKeysInSchema.Except(foreignKeysInDatabase, StringComparer.InvariantCultureIgnoreCase));
|
||||
foreach (var foreignKey in invalidForeignKeyDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", foreignKey));
|
||||
}
|
||||
|
||||
|
||||
//Primary keys:
|
||||
|
||||
//Add valid and invalid primary key differences to the result object
|
||||
var validPrimaryKeyDifferences = primaryKeysInDatabase.Intersect(primaryKeysInSchema);
|
||||
var validPrimaryKeyDifferences = primaryKeysInDatabase.Intersect(primaryKeysInSchema, StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var primaryKey in validPrimaryKeyDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(primaryKey);
|
||||
}
|
||||
var invalidPrimaryKeyDifferences = primaryKeysInDatabase.Except(primaryKeysInSchema);
|
||||
var invalidPrimaryKeyDifferences =
|
||||
primaryKeysInDatabase.Except(primaryKeysInSchema, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Union(primaryKeysInSchema.Except(primaryKeysInDatabase, StringComparer.InvariantCultureIgnoreCase));
|
||||
foreach (var primaryKey in invalidPrimaryKeyDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", primaryKey));
|
||||
}
|
||||
|
||||
//Constaints:
|
||||
|
||||
//NOTE: SD: The colIndex checks above should really take care of this but I need to keep this here because it was here before
|
||||
// and some schema validation checks might rely on this data remaining here!
|
||||
//Add valid and invalid index differences to the result object
|
||||
var validIndexDifferences = indexesInDatabase.Intersect(indexesInSchema);
|
||||
var validIndexDifferences = indexesInDatabase.Intersect(indexesInSchema, StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var index in validIndexDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(index);
|
||||
}
|
||||
var invalidIndexDifferences = indexesInDatabase.Except(indexesInSchema);
|
||||
var invalidIndexDifferences =
|
||||
indexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Union(indexesInSchema.Except(indexesInDatabase, StringComparer.InvariantCultureIgnoreCase));
|
||||
foreach (var index in invalidIndexDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", index));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
private void ValidateDbColumns(DatabaseSchemaResult result)
|
||||
{
|
||||
//Check columns in configured database against columns in schema
|
||||
var columnsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(_database);
|
||||
var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList();
|
||||
var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList();
|
||||
//Add valid and invalid column differences to the result object
|
||||
var validColumnDifferences = columnsPerTableInDatabase.Intersect(columnsPerTableInSchema, StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var column in validColumnDifferences)
|
||||
{
|
||||
result.ValidColumns.Add(column);
|
||||
}
|
||||
|
||||
var invalidColumnDifferences =
|
||||
columnsPerTableInDatabase.Except(columnsPerTableInSchema, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Union(columnsPerTableInSchema.Except(columnsPerTableInDatabase, StringComparer.InvariantCultureIgnoreCase));
|
||||
foreach (var column in invalidColumnDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Column", column));
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateDbTables(DatabaseSchemaResult result)
|
||||
{
|
||||
//Check tables in configured database against tables in schema
|
||||
var tablesInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetTablesInSchema(_database).ToList();
|
||||
var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList();
|
||||
//Add valid and invalid table differences to the result object
|
||||
var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema, StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var tableName in validTableDifferences)
|
||||
{
|
||||
result.ValidTables.Add(tableName);
|
||||
}
|
||||
|
||||
var invalidTableDifferences =
|
||||
tablesInDatabase.Except(tablesInSchema, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Union(tablesInSchema.Except(tablesInDatabase, StringComparer.InvariantCultureIgnoreCase));
|
||||
foreach (var tableName in invalidTableDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Table", tableName));
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateDbIndexes(DatabaseSchemaResult result)
|
||||
{
|
||||
//These are just column indexes NOT constraints or Keys
|
||||
//var colIndexesInDatabase = result.DbIndexDefinitions.Where(x => x.IndexName.InvariantStartsWith("IX_")).Select(x => x.IndexName).ToList();
|
||||
var colIndexesInDatabase = result.DbIndexDefinitions.Select(x => x.IndexName).ToList();
|
||||
var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList();
|
||||
|
||||
//Add valid and invalid index differences to the result object
|
||||
var validColIndexDifferences = colIndexesInDatabase.Intersect(indexesInSchema, StringComparer.InvariantCultureIgnoreCase);
|
||||
foreach (var index in validColIndexDifferences)
|
||||
{
|
||||
result.ValidIndexes.Add(index);
|
||||
}
|
||||
|
||||
var invalidColIndexDifferences =
|
||||
colIndexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Union(indexesInSchema.Except(colIndexesInDatabase, StringComparer.InvariantCultureIgnoreCase));
|
||||
foreach (var index in invalidColIndexDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Index", index));
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user