Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7b505fd90 | |||
| c5f7ac18fd | |||
| 10b8fd9fb9 | |||
| 24c053d671 | |||
| 44fc8be49e | |||
| 2a4e73c650 | |||
| f0a540eba2 | |||
| 12922f8413 | |||
| 85f054e3c1 | |||
| 470bf86ec0 | |||
| 9367f61952 | |||
| 3cabd8c318 | |||
| 4119380af5 | |||
| fc3b08e374 | |||
| a57abce96e | |||
| b260f6c6de | |||
| c96e017e65 | |||
| 4f596d20a9 | |||
| 343e462473 | |||
| db414e8045 | |||
| 54e460cf5b | |||
| ba64768d8d | |||
| 6710ac8c85 | |||
| 1f98b76da0 | |||
| 519eb9d641 | |||
| 931db6f0b1 | |||
| f24c56d1ba | |||
| 44608c3122 | |||
| 90f2fc4cd9 | |||
| 24c7dee5d0 | |||
| 12417c0c48 | |||
| d4919ff8c4 | |||
| b2acb97639 | |||
| 28debbda1b | |||
| c0a2a78f3d | |||
| 3f7bfe0b3a | |||
| e0d281bb4b | |||
| b7d37af933 | |||
| 3f9cfbb422 | |||
| 2f3d926c08 | |||
| 594c3b8a85 | |||
| 41244485b1 | |||
| ede342feba | |||
| a15bdba5d7 | |||
| 7d4a9998ca | |||
| bde439d102 | |||
| ba501dbbb8 | |||
| 0a53f7636c | |||
| 6e6d552441 | |||
| f75e0cf4ba | |||
| 0dc3bff01a | |||
| 358dd7f32b | |||
| 6531d027fc | |||
| d11e787624 | |||
| 055ae0d126 | |||
| 77969960d9 | |||
| 52b1a08912 | |||
| 1a9f336a59 | |||
| 9ba08f275e | |||
| aadd0c9129 | |||
| b3b79a792f | |||
| 59cd4b5c5c | |||
| f5f9ff29ce | |||
| a10b59d03b | |||
| e6b1ecb851 | |||
| 69d6609a3b | |||
| 2196ab3713 | |||
| 89be1cf5d2 | |||
| 2041e85b9e | |||
| 6c2f0e404f | |||
| d5e66252dc | |||
| c2359a96f8 | |||
| 1df65bc3ce | |||
| 530a80d7ea | |||
| 8be0f68390 | |||
| 05cb30d79c | |||
| c472d4975e | |||
| 0e31fcf3db | |||
| 13ed3303f5 | |||
| f200ab423d | |||
| d889d3e385 | |||
| 0bf27fa319 | |||
| 466a37aab8 | |||
| 4ab2130d7d | |||
| 256ceef875 | |||
| 2acde54880 | |||
| a92d255e4b | |||
| dc62272e6e | |||
| 60f6a60ca9 | |||
| eef8d21112 | |||
| 6a374cbfa6 | |||
| ccb8ac4cfc | |||
| 5de21734c0 | |||
| 18deb8ad99 | |||
| 3426ae3722 | |||
| d04510f5f2 | |||
| 84c0682f16 | |||
| 53bbc5f922 | |||
| 56d2230251 | |||
| 62f21d3cee | |||
| b9c90af8be | |||
| 7a661c1b48 | |||
| c871a711dd | |||
| d671caf3ab | |||
| d412d90b17 | |||
| 2f74181262 | |||
| 45fd23ff02 | |||
| 4e2fb8e5dc | |||
| afbceca184 | |||
| 1b8c68af02 | |||
| 98430fd573 | |||
| 4a547ba1c9 | |||
| 59f39fd535 | |||
| b4ca04596c | |||
| 2d94ac7a19 | |||
| 4c97c689e9 | |||
| f2f4c23c80 | |||
| 67ea15706e | |||
| 5cc75b8cc3 | |||
| 653ac66ff3 | |||
| 3f7e593bc2 | |||
| 39505cd868 | |||
| 0daaa3e785 | |||
| 4050a375bc | |||
| da27108d0d | |||
| a058f26462 | |||
| c8f0f05570 | |||
| 347ed2896a | |||
| 5c40a1f9e9 | |||
| afa39866ad | |||
| 7254db40eb | |||
| 04481c33e7 | |||
| 4c107470c3 | |||
| 4b39f490f3 | |||
| c607ceda48 | |||
| d4acd4629a | |||
| b413b7b5af | |||
| 5bc66c5b7f | |||
| 0415e910dc | |||
| 960040e51e | |||
| 90136c524c | |||
| 8d7f496f7c | |||
| f62a9ed199 | |||
| bc8b8a69b8 | |||
| 9de3acfae2 | |||
| 19b24b5109 | |||
| 3aaa33ebe9 | |||
| 4ae7a32e29 | |||
| 87814fa43c | |||
| dfbadb1550 | |||
| 0a49d54a85 |
@@ -1,6 +1,6 @@
|
||||
Umbraco CMS
|
||||
===========
|
||||
The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 350,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
|
||||
The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 390,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
|
||||
|
||||
[](https://vimeo.com/172382998/)
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
<!-- AutoMapper can not be updated due to: https://github.com/AutoMapper/AutoMapper/issues/373#issuecomment-127644405 -->
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.70, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.4.5, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.6.6, 5.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.80, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.8.0, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
|
||||
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
|
||||
@@ -103,4 +103,4 @@
|
||||
<file src="..\_BuildOutput\bin\UmbracoExamine.pdb" target="lib" />
|
||||
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
|
||||
</files>
|
||||
</package>
|
||||
</package>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.5, 4.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -43,6 +44,7 @@
|
||||
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
|
||||
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
|
||||
<file src="tools\processing.config.install.xdt" target="Content\Config\imageprocessor\processing.config.install.xdt" />
|
||||
<file src="build\**" target="build" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -71,6 +71,7 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\ImageProcessor.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll) { Remove-Item $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<processing xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="SetAttributes(preserveExifMetaData)" preserveExifMetaData="true" />
|
||||
@@ -1,2 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.5.5
|
||||
7.5.8
|
||||
@@ -49,13 +49,9 @@
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
using System.Resources;
|
||||
|
||||
[assembly: AssemblyCompany("Umbraco")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2016")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.5.5")]
|
||||
[assembly: AssemblyInformationalVersion("7.5.5")]
|
||||
[assembly: AssemblyFileVersion("7.5.8")]
|
||||
[assembly: AssemblyInformationalVersion("7.5.8")]
|
||||
@@ -64,7 +64,8 @@ namespace Umbraco.Core.Cache
|
||||
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
|
||||
public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:";
|
||||
|
||||
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
|
||||
[Obsolete("No longer used and will be removed in v8")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
|
||||
@@ -4,8 +4,7 @@ using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
|
||||
internal class ContentElement : ConfigurationElement, IContentSection
|
||||
internal class ContentElement : UmbracoConfigurationElement, IContentSection
|
||||
{
|
||||
[ConfigurationProperty("imaging")]
|
||||
internal ContentImagingElement Imaging
|
||||
@@ -22,25 +21,13 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
[ConfigurationProperty("ResolveUrlsFromTextString")]
|
||||
internal InnerTextConfigurationElement<bool> ResolveUrlsFromTextString
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["ResolveUrlsFromTextString"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement<bool>("ResolveUrlsFromTextString", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("UploadAllowDirectories")]
|
||||
internal InnerTextConfigurationElement<bool> UploadAllowDirectories
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["UploadAllowDirectories"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("UploadAllowDirectories", true); }
|
||||
}
|
||||
|
||||
public IEnumerable<IContentErrorPage> Error404Collection
|
||||
@@ -63,121 +50,61 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
[ConfigurationProperty("ensureUniqueNaming")]
|
||||
internal InnerTextConfigurationElement<bool> EnsureUniqueNaming
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["ensureUniqueNaming"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("ensureUniqueNaming", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("TidyEditorContent")]
|
||||
internal InnerTextConfigurationElement<bool> TidyEditorContent
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["TidyEditorContent"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("TidyEditorContent", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("TidyCharEncoding")]
|
||||
internal InnerTextConfigurationElement<string> TidyCharEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["TidyCharEncoding"],
|
||||
//set the default
|
||||
"UTF8");
|
||||
}
|
||||
get { return GetOptionalTextElement("TidyCharEncoding", "UTF8"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("XmlCacheEnabled")]
|
||||
internal InnerTextConfigurationElement<bool> XmlCacheEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["XmlCacheEnabled"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("XmlCacheEnabled", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("ContinouslyUpdateXmlDiskCache")]
|
||||
internal InnerTextConfigurationElement<bool> ContinouslyUpdateXmlDiskCache
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["ContinouslyUpdateXmlDiskCache"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("ContinouslyUpdateXmlDiskCache", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("XmlContentCheckForDiskChanges")]
|
||||
internal InnerTextConfigurationElement<bool> XmlContentCheckForDiskChanges
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["XmlContentCheckForDiskChanges"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("XmlContentCheckForDiskChanges", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("EnableSplashWhileLoading")]
|
||||
internal InnerTextConfigurationElement<bool> EnableSplashWhileLoading
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["EnableSplashWhileLoading"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("EnableSplashWhileLoading", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("PropertyContextHelpOption")]
|
||||
internal InnerTextConfigurationElement<string> PropertyContextHelpOption
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["PropertyContextHelpOption"],
|
||||
//set the default
|
||||
"text");
|
||||
}
|
||||
get { return GetOptionalTextElement("PropertyContextHelpOption", "text"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("UseLegacyXmlSchema")]
|
||||
internal InnerTextConfigurationElement<bool> UseLegacyXmlSchema
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["UseLegacyXmlSchema"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("UseLegacyXmlSchema", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("ForceSafeAliases")]
|
||||
internal InnerTextConfigurationElement<bool> ForceSafeAliases
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["ForceSafeAliases"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("ForceSafeAliases", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("PreviewBadge")]
|
||||
@@ -185,123 +112,63 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["PreviewBadge"],
|
||||
//set the default
|
||||
@"<a id=""umbracoPreviewBadge"" style=""position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;"" href=""{0}/endPreview.aspx?redir={2}""><span style=""display:none;"">In Preview Mode - click to end</span></a>");
|
||||
return GetOptionalTextElement("PreviewBadge", @"<a id=""umbracoPreviewBadge"" style=""position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;"" href=""{0}/endPreview.aspx?redir={2}""><span style=""display:none;"">In Preview Mode - click to end</span></a>");
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty("UmbracoLibraryCacheDuration")]
|
||||
internal InnerTextConfigurationElement<int> UmbracoLibraryCacheDuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<int>(
|
||||
(InnerTextConfigurationElement<int>)this["UmbracoLibraryCacheDuration"],
|
||||
//set the default
|
||||
1800);
|
||||
|
||||
}
|
||||
get { return GetOptionalTextElement("UmbracoLibraryCacheDuration", 1800); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("MacroErrors")]
|
||||
internal InnerTextConfigurationElement<MacroErrorBehaviour> MacroErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
return new OptionalInnerTextConfigurationElement<MacroErrorBehaviour>(
|
||||
(InnerTextConfigurationElement<MacroErrorBehaviour>)this["MacroErrors"],
|
||||
//set the default
|
||||
MacroErrorBehaviour.Inline);
|
||||
}
|
||||
get { return GetOptionalTextElement("MacroErrors", MacroErrorBehaviour.Inline); }
|
||||
}
|
||||
|
||||
[Obsolete("This is here so that if this config element exists we won't get a YSOD, it is not used whatsoever and will be removed in future versions")]
|
||||
[ConfigurationProperty("DocumentTypeIconList")]
|
||||
internal InnerTextConfigurationElement<IconPickerBehaviour> DocumentTypeIconList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<IconPickerBehaviour>(
|
||||
(InnerTextConfigurationElement<IconPickerBehaviour>)this["DocumentTypeIconList"],
|
||||
//set the default
|
||||
IconPickerBehaviour.HideFileDuplicates);
|
||||
}
|
||||
get { return GetOptionalTextElement("DocumentTypeIconList", IconPickerBehaviour.HideFileDuplicates); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("disallowedUploadFiles")]
|
||||
internal CommaDelimitedConfigurationElement DisallowedUploadFiles
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalCommaDelimitedConfigurationElement(
|
||||
(CommaDelimitedConfigurationElement)this["disallowedUploadFiles"],
|
||||
//set the default
|
||||
new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" });
|
||||
|
||||
}
|
||||
get { return GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"}); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("cloneXmlContent")]
|
||||
internal InnerTextConfigurationElement<bool> CloneXmlContent
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["cloneXmlContent"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("cloneXmlContent", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("GlobalPreviewStorageEnabled")]
|
||||
internal InnerTextConfigurationElement<bool> GlobalPreviewStorageEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["GlobalPreviewStorageEnabled"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("GlobalPreviewStorageEnabled", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("defaultDocumentTypeProperty")]
|
||||
internal InnerTextConfigurationElement<string> DefaultDocumentTypeProperty
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["defaultDocumentTypeProperty"],
|
||||
//set the default
|
||||
"Textstring");
|
||||
}
|
||||
get { return GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("EnableInheritedDocumentTypes")]
|
||||
internal InnerTextConfigurationElement<bool> EnableInheritedDocumentTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>) this["EnableInheritedDocumentTypes"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("EnableInheritedDocumentTypes", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("EnableInheritedMediaTypes")]
|
||||
internal InnerTextConfigurationElement<bool> EnableInheritedMediaTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["EnableInheritedMediaTypes"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("EnableInheritedMediaTypes", true); }
|
||||
}
|
||||
|
||||
string IContentSection.NotificationEmailAddress
|
||||
|
||||
@@ -3,42 +3,24 @@ using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class ContentScriptEditorElement : ConfigurationElement
|
||||
internal class ContentScriptEditorElement : UmbracoConfigurationElement
|
||||
{
|
||||
[ConfigurationProperty("scriptFolderPath")]
|
||||
internal InnerTextConfigurationElement<string> ScriptFolderPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["scriptFolderPath"],
|
||||
//set the default
|
||||
"/scripts");
|
||||
}
|
||||
get { return GetOptionalTextElement("scriptFolderPath", "/scripts"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("scriptFileTypes")]
|
||||
internal OptionalCommaDelimitedConfigurationElement ScriptFileTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalCommaDelimitedConfigurationElement(
|
||||
(OptionalCommaDelimitedConfigurationElement)this["scriptFileTypes"],
|
||||
//set the default
|
||||
new[] { "js", "xml" });
|
||||
}
|
||||
get { return GetOptionalDelimitedElement("scriptFileTypes", new[] {"js", "xml"}); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("scriptDisableEditor")]
|
||||
internal InnerTextConfigurationElement<bool> ScriptEditorDisable
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>) this["scriptDisableEditor"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("scriptDisableEditor", false); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-29
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class ImagingAutoFillUploadFieldElement : ConfigurationElement, IImagingAutoFillUploadField
|
||||
internal class ImagingAutoFillUploadFieldElement : UmbracoConfigurationElement, IImagingAutoFillUploadField
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow setting internally so we can create a default
|
||||
@@ -17,49 +17,25 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
[ConfigurationProperty("widthFieldAlias")]
|
||||
internal InnerTextConfigurationElement<string> WidthFieldAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["widthFieldAlias"],
|
||||
//set the default
|
||||
"umbracoWidth");
|
||||
}
|
||||
get { return GetOptionalTextElement("widthFieldAlias", "umbracoWidth"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("heightFieldAlias")]
|
||||
internal InnerTextConfigurationElement<string> HeightFieldAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["heightFieldAlias"],
|
||||
//set the default
|
||||
"umbracoHeight");
|
||||
}
|
||||
get { return GetOptionalTextElement("heightFieldAlias", "umbracoHeight"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("lengthFieldAlias")]
|
||||
internal InnerTextConfigurationElement<string> LengthFieldAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["lengthFieldAlias"],
|
||||
//set the default
|
||||
"umbracoBytes");
|
||||
}
|
||||
get { return GetOptionalTextElement("lengthFieldAlias", "umbracoBytes"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("extensionFieldAlias")]
|
||||
internal InnerTextConfigurationElement<string> ExtensionFieldAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["extensionFieldAlias"],
|
||||
//set the default
|
||||
"umbracoExtension");
|
||||
}
|
||||
get { return GetOptionalTextElement("extensionFieldAlias", "umbracoExtension"); }
|
||||
}
|
||||
|
||||
string IImagingAutoFillUploadField.Alias
|
||||
|
||||
@@ -3,67 +3,37 @@ using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class LoggingElement : ConfigurationElement, ILoggingSection
|
||||
internal class LoggingElement : UmbracoConfigurationElement, ILoggingSection
|
||||
{
|
||||
|
||||
[ConfigurationProperty("autoCleanLogs")]
|
||||
internal InnerTextConfigurationElement<bool> AutoCleanLogs
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["autoCleanLogs"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("autoCleanLogs", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("enableLogging")]
|
||||
internal InnerTextConfigurationElement<bool> EnableLogging
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["enableLogging"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("enableLogging", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("enableAsyncLogging")]
|
||||
internal InnerTextConfigurationElement<bool> EnableAsyncLogging
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["enableAsyncLogging"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("enableAsyncLogging", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("cleaningMiliseconds")]
|
||||
internal InnerTextConfigurationElement<int> CleaningMiliseconds
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<int>(
|
||||
(InnerTextConfigurationElement<int>)this["cleaningMiliseconds"],
|
||||
//set the default
|
||||
-1);
|
||||
}
|
||||
get { return GetOptionalTextElement("cleaningMiliseconds", -1); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("maxLogAge")]
|
||||
internal InnerTextConfigurationElement<int> MaxLogAge
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<int>(
|
||||
(InnerTextConfigurationElement<int>)this["maxLogAge"],
|
||||
//set the default
|
||||
-1);
|
||||
}
|
||||
get { return GetOptionalTextElement("maxLogAge", -1); }
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(DisabledLogTypesCollection), AddItemName = "logTypeAlias")]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class NotificationsElement : ConfigurationElement
|
||||
internal class NotificationsElement : UmbracoConfigurationElement
|
||||
{
|
||||
[ConfigurationProperty("email")]
|
||||
internal InnerTextConfigurationElement<string> NotificationEmailAddress
|
||||
@@ -13,13 +13,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
[ConfigurationProperty("disableHtmlEmail")]
|
||||
internal InnerTextConfigurationElement<bool> DisableHtmlEmail
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>) this["disableHtmlEmail"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("disableHtmlEmail", false); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,30 +5,18 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class RequestHandlerElement : ConfigurationElement, IRequestHandlerSection
|
||||
internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSection
|
||||
{
|
||||
[ConfigurationProperty("useDomainPrefixes")]
|
||||
public InnerTextConfigurationElement<bool> UseDomainPrefixes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["useDomainPrefixes"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("useDomainPrefixes", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("addTrailingSlash")]
|
||||
public InnerTextConfigurationElement<bool> AddTrailingSlash
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["addTrailingSlash"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("addTrailingSlash", true); }
|
||||
}
|
||||
|
||||
private UrlReplacingElement _defaultUrlReplacing;
|
||||
|
||||
@@ -2,66 +2,36 @@
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class SecurityElement : ConfigurationElement, ISecuritySection
|
||||
internal class SecurityElement : UmbracoConfigurationElement, ISecuritySection
|
||||
{
|
||||
[ConfigurationProperty("keepUserLoggedIn")]
|
||||
internal InnerTextConfigurationElement<bool> KeepUserLoggedIn
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["keepUserLoggedIn"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("keepUserLoggedIn", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("hideDisabledUsersInBackoffice")]
|
||||
internal InnerTextConfigurationElement<bool> HideDisabledUsersInBackoffice
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["hideDisabledUsersInBackoffice"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("hideDisabledUsersInBackoffice", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("allowPasswordReset")]
|
||||
internal InnerTextConfigurationElement<bool> AllowPasswordReset
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["allowPasswordReset"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("allowPasswordReset", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("authCookieName")]
|
||||
internal InnerTextConfigurationElement<string> AuthCookieName
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["authCookieName"],
|
||||
//set the default
|
||||
Constants.Web.AuthCookieName);
|
||||
}
|
||||
get { return GetOptionalTextElement("authCookieName", Constants.Web.AuthCookieName); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("authCookieDomain")]
|
||||
internal InnerTextConfigurationElement<string> AuthCookieDomain
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<string>(
|
||||
(InnerTextConfigurationElement<string>)this["authCookieDomain"],
|
||||
//set the default
|
||||
null);
|
||||
}
|
||||
get { return GetOptionalTextElement<string>("authCookieDomain", null); }
|
||||
}
|
||||
|
||||
bool ISecuritySection.KeepUserLoggedIn
|
||||
|
||||
@@ -3,55 +3,31 @@ using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class TemplatesElement : ConfigurationElement, ITemplatesSection
|
||||
internal class TemplatesElement : UmbracoConfigurationElement, ITemplatesSection
|
||||
{
|
||||
[ConfigurationProperty("useAspNetMasterPages")]
|
||||
internal InnerTextConfigurationElement<bool> UseAspNetMasterPages
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["useAspNetMasterPages"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("useAspNetMasterPages", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("enableSkinSupport")]
|
||||
internal InnerTextConfigurationElement<bool> EnableSkinSupport
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["enableSkinSupport"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
get { return GetOptionalTextElement("enableSkinSupport", true); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("defaultRenderingEngine", IsRequired = true)]
|
||||
internal InnerTextConfigurationElement<RenderingEngine> DefaultRenderingEngine
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<RenderingEngine>(
|
||||
(InnerTextConfigurationElement<RenderingEngine>)this["defaultRenderingEngine"],
|
||||
//set the default
|
||||
RenderingEngine.Mvc);
|
||||
}
|
||||
get { return GetOptionalTextElement("defaultRenderingEngine", RenderingEngine.Mvc); }
|
||||
}
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
[ConfigurationProperty("enableTemplateFolders")]
|
||||
internal InnerTextConfigurationElement<bool> EnableTemplateFolders
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["enableTemplateFolders"],
|
||||
//set the default
|
||||
false);
|
||||
}
|
||||
get { return GetOptionalTextElement("enableTemplateFolders", false); }
|
||||
}
|
||||
|
||||
bool ITemplatesSection.UseAspNetMasterPages
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class with shared helper methods
|
||||
/// </summary>
|
||||
internal class UmbracoConfigurationElement : ConfigurationElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Used so the RawElement types are not re-created every time they are accessed
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, RawXmlConfigurationElement> _rawElements = new ConcurrentDictionary<string, RawXmlConfigurationElement>();
|
||||
|
||||
protected OptionalInnerTextConfigurationElement<T> GetOptionalTextElement<T>(string name, T defaultVal)
|
||||
{
|
||||
return (OptionalInnerTextConfigurationElement<T>) _rawElements.GetOrAdd(
|
||||
name,
|
||||
s => new OptionalInnerTextConfigurationElement<T>(
|
||||
(InnerTextConfigurationElement<T>) this[s],
|
||||
//set the default
|
||||
defaultVal));
|
||||
}
|
||||
|
||||
protected OptionalCommaDelimitedConfigurationElement GetOptionalDelimitedElement(string name, string[] defaultVal)
|
||||
{
|
||||
return (OptionalCommaDelimitedConfigurationElement) _rawElements.GetOrAdd(
|
||||
name,
|
||||
s => new OptionalCommaDelimitedConfigurationElement(
|
||||
(CommaDelimitedConfigurationElement) this[name],
|
||||
//set the default
|
||||
defaultVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.5.5");
|
||||
private static readonly Version Version = new Version("7.5.8");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -415,7 +415,7 @@ namespace Umbraco.Core
|
||||
|
||||
if (currentTry == 5)
|
||||
{
|
||||
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database.");
|
||||
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but Umbraco cannot connect to the database.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ namespace Umbraco.Core
|
||||
private string _connectionString;
|
||||
private string _providerName;
|
||||
private DatabaseSchemaResult _result;
|
||||
private DateTime? _connectionLastChecked = null;
|
||||
|
||||
/// <summary>
|
||||
/// The number of minutes to throttle the checks to CanConnect
|
||||
/// </summary>
|
||||
private const int ConnectionCheckMinutes = 1;
|
||||
|
||||
[Obsolete("Use the constructor specifying all dependencies instead")]
|
||||
public DatabaseContext(IDatabaseFactory factory)
|
||||
@@ -110,13 +116,28 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsDatabaseConfigured == false) return false;
|
||||
var canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider);
|
||||
LogHelper.Info<DatabaseContext>("CanConnect = " + canConnect);
|
||||
return canConnect;
|
||||
if (IsDatabaseConfigured == false)
|
||||
return false;
|
||||
|
||||
//Don't check again if the timeout period hasn't elapsed
|
||||
//this ensures we don't keep checking the connection too many times in a row like during startup.
|
||||
//Do check if the _connectionLastChecked is null which means we're just initializing or it could
|
||||
//not connect last time it was checked.
|
||||
if ((_connectionLastChecked.HasValue && (DateTime.Now - _connectionLastChecked.Value).TotalMinutes > ConnectionCheckMinutes)
|
||||
|| _connectionLastChecked.HasValue == false)
|
||||
{
|
||||
var canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider);
|
||||
LogHelper.Info<DatabaseContext>("CanConnect = " + canConnect);
|
||||
|
||||
_connectionLastChecked = canConnect == false ? null : (DateTime?) DateTime.Now;
|
||||
return canConnect;
|
||||
}
|
||||
|
||||
return _connectionLastChecked.HasValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configured umbraco db connection string.
|
||||
/// </summary>
|
||||
@@ -182,15 +203,10 @@ namespace Umbraco.Core
|
||||
var path = Path.Combine(GlobalSettings.FullpathToRoot, "App_Data", "Umbraco.sdf");
|
||||
if (File.Exists(path) == false)
|
||||
{
|
||||
var engine = new SqlCeEngine(connectionString);
|
||||
engine.CreateDatabase();
|
||||
|
||||
// SD: Pretty sure this should be in a using clause but i don't want to cause unknown side-effects here
|
||||
// since it's been like this for quite some time
|
||||
//using (var engine = new SqlCeEngine(connectionString))
|
||||
//{
|
||||
// engine.CreateDatabase();
|
||||
//}
|
||||
using (var engine = new SqlCeEngine(connectionString))
|
||||
{
|
||||
engine.CreateDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
Initialize(providerName);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ImageProcessor.Common.Exceptions;
|
||||
|
||||
using ImageProcessor.Common.Exceptions;
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A logger for explicitly logging ImageProcessor exceptions.
|
||||
|
||||
@@ -404,8 +404,7 @@ namespace Umbraco.Core.Models
|
||||
return content.Properties
|
||||
.Where(property => propertyGroup.PropertyTypes
|
||||
.Select(propertyType => propertyType.Id)
|
||||
.Contains(property.PropertyTypeId))
|
||||
.OrderBy(x => x.PropertyType.SortOrder);
|
||||
.Contains(property.PropertyTypeId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a ContentType, which Media is based on
|
||||
/// </summary
|
||||
/// </summary>
|
||||
public interface IMediaType : IContentTypeComposition
|
||||
{
|
||||
|
||||
|
||||
@@ -1,15 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.UI.WebControls;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal static class UmbracoEntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Does a quick check on the entity's set path to ensure that it's valid and consistent
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static void ValidatePathWithException(this NodeDto entity)
|
||||
{
|
||||
//don't validate if it's empty and it has no id
|
||||
if (entity.NodeId == default(int) && entity.Path.IsNullOrWhiteSpace())
|
||||
return;
|
||||
|
||||
if (entity.Path.IsNullOrWhiteSpace())
|
||||
throw new InvalidDataException(string.Format("The content item {0} has an empty path: {1} with parentID: {2}", entity.NodeId, entity.Path, entity.ParentId));
|
||||
|
||||
var pathParts = entity.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (pathParts.Length < 2)
|
||||
{
|
||||
//a path cannot be less than 2 parts, at a minimum it must be root (-1) and it's own id
|
||||
throw new InvalidDataException(string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", entity.NodeId, entity.Path, entity.ParentId));
|
||||
}
|
||||
|
||||
if (entity.ParentId != default(int) && pathParts[pathParts.Length - 2] != entity.ParentId.ToInvariantString())
|
||||
{
|
||||
//the 2nd last id in the path must be it's parent id
|
||||
throw new InvalidDataException(string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", entity.NodeId, entity.Path, entity.ParentId));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does a quick check on the entity's set path to ensure that it's valid and consistent
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ValidatePath(this IUmbracoEntity entity)
|
||||
{
|
||||
//don't validate if it's empty and it has no id
|
||||
if (entity.HasIdentity == false && entity.Path.IsNullOrWhiteSpace())
|
||||
return true;
|
||||
|
||||
if (entity.Path.IsNullOrWhiteSpace())
|
||||
return false;
|
||||
|
||||
var pathParts = entity.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (pathParts.Length < 2)
|
||||
{
|
||||
//a path cannot be less than 2 parts, at a minimum it must be root (-1) and it's own id
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entity.ParentId != default(int) && pathParts[pathParts.Length - 2] != entity.ParentId.ToInvariantString())
|
||||
{
|
||||
//the 2nd last id in the path must be it's parent id
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will validate the entity's path and if it's invalid it will fix it, if fixing is required it will recursively
|
||||
/// check and fix all ancestors if required.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="getParent">A callback specified to retrieve the parent entity of the entity</param>
|
||||
/// <param name="update">A callback specified to update a fixed entity</param>
|
||||
public static void EnsureValidPath<T>(this T entity,
|
||||
ILogger logger,
|
||||
Func<T, T> getParent,
|
||||
Action<T> update)
|
||||
where T: IUmbracoEntity
|
||||
{
|
||||
if (entity.HasIdentity == false)
|
||||
throw new InvalidOperationException("Could not ensure the entity path, the entity has not been assigned an identity");
|
||||
|
||||
if (entity.ValidatePath() == false)
|
||||
{
|
||||
logger.Warn(typeof(UmbracoEntityExtensions), string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", entity.Id, entity.Path, entity.ParentId));
|
||||
if (entity.ParentId == -1)
|
||||
{
|
||||
entity.Path = string.Concat("-1,", entity.Id);
|
||||
//path changed, update it
|
||||
update(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parent = getParent(entity);
|
||||
if (parent == null)
|
||||
throw new NullReferenceException("Could not ensure path for entity " + entity.Id + " could not resolve it's parent " + entity.ParentId);
|
||||
|
||||
//the parent must also be valid!
|
||||
parent.EnsureValidPath(logger, getParent, update);
|
||||
|
||||
entity.Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
//path changed, update it
|
||||
update(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasChildren(this IUmbracoEntity entity)
|
||||
{
|
||||
|
||||
@@ -4,9 +4,11 @@ using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
@@ -69,6 +71,38 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetConnStringExSecurityInfo(this IDbConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (connection is SqlConnection)
|
||||
{
|
||||
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
|
||||
return string.Format("DataSource: {0}, InitialCatalog: {1}", builder.DataSource, builder.InitialCatalog);
|
||||
}
|
||||
|
||||
if (connection is SqlCeConnection)
|
||||
{
|
||||
var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString);
|
||||
return string.Format("DataSource: {0}", builder.DataSource);
|
||||
}
|
||||
|
||||
if (connection is MySqlConnection)
|
||||
{
|
||||
var builder = new MySqlConnectionStringBuilder(connection.ConnectionString);
|
||||
return string.Format("Server: {0}, Database: {1}", builder.Server, builder.Database);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WarnWithException(typeof(DbConnectionExtensions),
|
||||
"Could not resolve connection string parameters", ex);
|
||||
return "(Could not resolve)";
|
||||
}
|
||||
|
||||
throw new ArgumentException(string.Format("The connection type {0} is not supported", connection.GetType()));
|
||||
}
|
||||
|
||||
public static bool IsAvailable(this IDbConnection connection)
|
||||
{
|
||||
try
|
||||
@@ -79,7 +113,8 @@ namespace Umbraco.Core.Persistence
|
||||
catch (DbException exc)
|
||||
{
|
||||
// Don't swallow this error, the exception is super handy for knowing "why" its not available
|
||||
LogHelper.WarnWithException<IDbConnection>("Configured database is reporting as not being available!", exc);
|
||||
LogHelper.WarnWithException(typeof(DbConnectionExtensions),
|
||||
"Configured database is reporting as not being available! {0}", exc, connection.GetConnStringExSecurityInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,15 +27,15 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
#region Implementation of IEntityFactory<IContent,DocumentDto>
|
||||
|
||||
public IContent BuildEntity(DocumentDto dto)
|
||||
public static IContent BuildEntity(DocumentDto dto, IContentType contentType)
|
||||
{
|
||||
var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType);
|
||||
var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, contentType);
|
||||
|
||||
try
|
||||
{
|
||||
content.DisableChangeTracking();
|
||||
|
||||
content.Id = _id;
|
||||
content.Id = dto.NodeId;
|
||||
content.Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId;
|
||||
content.Name = dto.Text;
|
||||
content.NodeName = dto.ContentVersionDto.ContentDto.NodeDto.Text;
|
||||
@@ -49,8 +49,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
content.Published = dto.Published;
|
||||
content.CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate;
|
||||
content.UpdateDate = dto.ContentVersionDto.VersionDate;
|
||||
content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?) null;
|
||||
content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?) null;
|
||||
content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null;
|
||||
content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null;
|
||||
content.Version = dto.ContentVersionDto.VersionId;
|
||||
content.PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished;
|
||||
content.PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId;
|
||||
@@ -64,6 +64,13 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
content.EnableChangeTracking();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Use the static BuildEntity instead so we don't have to allocate one of these objects everytime we want to map values")]
|
||||
public IContent BuildEntity(DocumentDto dto)
|
||||
{
|
||||
return BuildEntity(dto, _contentType);
|
||||
}
|
||||
|
||||
public DocumentDto BuildDto(IContent entity)
|
||||
|
||||
@@ -27,15 +27,15 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
#region Implementation of IEntityFactory<IMedia,ContentVersionDto>
|
||||
|
||||
public IMedia BuildEntity(ContentVersionDto dto)
|
||||
public static IMedia BuildEntity(ContentVersionDto dto, IMediaType contentType)
|
||||
{
|
||||
var media = new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, _contentType);
|
||||
var media = new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, contentType);
|
||||
|
||||
try
|
||||
{
|
||||
media.DisableChangeTracking();
|
||||
|
||||
media.Id = _id;
|
||||
media.Id = dto.NodeId;
|
||||
media.Key = dto.ContentDto.NodeDto.UniqueId;
|
||||
media.Path = dto.ContentDto.NodeDto.Path;
|
||||
media.CreatorId = dto.ContentDto.NodeDto.UserId.Value;
|
||||
@@ -55,6 +55,13 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
media.EnableChangeTracking();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Use the static BuildEntity instead so we don't have to allocate one of these objects everytime we want to map values")]
|
||||
public IMedia BuildEntity(ContentVersionDto dto)
|
||||
{
|
||||
return BuildEntity(dto, _contentType);
|
||||
}
|
||||
|
||||
public ContentVersionDto BuildDto(IMedia entity)
|
||||
|
||||
@@ -30,11 +30,11 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
_updateDate = updateDate;
|
||||
}
|
||||
|
||||
public IEnumerable<Property> BuildEntity(PropertyDataDto[] dtos)
|
||||
public static IEnumerable<Property> BuildEntity(IReadOnlyCollection<PropertyDataDto> dtos, PropertyType[] compositionTypeProperties, DateTime createDate, DateTime updateDate)
|
||||
{
|
||||
var properties = new List<Property>();
|
||||
|
||||
foreach (var propertyType in _compositionTypeProperties)
|
||||
foreach (var propertyType in compositionTypeProperties)
|
||||
{
|
||||
var propertyDataDto = dtos.LastOrDefault(x => x.PropertyTypeId == propertyType.Id);
|
||||
var property = propertyDataDto == null
|
||||
@@ -47,8 +47,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
property.DisableChangeTracking();
|
||||
|
||||
property.CreateDate = _createDate;
|
||||
property.UpdateDate = _updateDate;
|
||||
property.CreateDate = createDate;
|
||||
property.UpdateDate = updateDate;
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
property.ResetDirtyProperties(false);
|
||||
properties.Add(property);
|
||||
@@ -57,12 +57,18 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
property.EnableChangeTracking();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
[Obsolete("Use the static method instead, there's no reason to allocate one of these classes everytime we want to map values")]
|
||||
public IEnumerable<Property> BuildEntity(PropertyDataDto[] dtos)
|
||||
{
|
||||
return BuildEntity(dtos, _compositionTypeProperties, _createDate, _updateDate);
|
||||
}
|
||||
|
||||
public IEnumerable<PropertyDataDto> BuildDto(IEnumerable<Property> properties)
|
||||
{
|
||||
var propertyDataDtos = new List<PropertyDataDto>();
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Umbraco.Core.Persistence
|
||||
return sql.From(sqlSyntax.GetQuotedTableName(tableName));
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload specifying ISqlSyntaxProvider instead")]
|
||||
public static Sql Where<T>(this Sql sql, Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<T>();
|
||||
@@ -34,6 +35,13 @@ namespace Umbraco.Core.Persistence
|
||||
return sql.Where(whereExpression, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
public static Sql Where<T>(this Sql sql, Expression<Func<T, bool>> predicate, ISqlSyntaxProvider sqlSyntax)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<T>(sqlSyntax);
|
||||
var whereExpression = expresionist.Visit(predicate);
|
||||
return sql.Where(whereExpression, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
private static string GetFieldName<T>(Expression<Func<T, object>> fieldSelector, ISqlSyntaxProvider sqlSyntax)
|
||||
{
|
||||
var field = ExpressionHelper.FindProperty(fieldSelector) as PropertyInfo;
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload the specifies a SqlSyntaxProvider")]
|
||||
public ModelToSqlExpressionVisitor()
|
||||
: this(SqlSyntaxContext.SqlSyntaxProvider, MappingResolver.Current.ResolveMapperByType(typeof(T)))
|
||||
{ }
|
||||
|
||||
@@ -14,12 +14,19 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
private readonly Database.PocoData _pd;
|
||||
|
||||
public PocoToSqlExpressionVisitor()
|
||||
: base(SqlSyntaxContext.SqlSyntaxProvider)
|
||||
|
||||
public PocoToSqlExpressionVisitor(ISqlSyntaxProvider syntaxProvider)
|
||||
: base(syntaxProvider)
|
||||
{
|
||||
_pd = new Database.PocoData(typeof(T));
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload the specifies a SqlSyntaxProvider")]
|
||||
public PocoToSqlExpressionVisitor()
|
||||
: this(SqlSyntaxContext.SqlSyntaxProvider)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
if (m.Expression != null &&
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal enum BaseQueryType
|
||||
{
|
||||
Full,
|
||||
Ids,
|
||||
Count
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
@@ -70,69 +70,90 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<IContent> PerformGetAll(params int[] ids)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
if (ids.Any())
|
||||
Func<Sql, Sql> translate = s =>
|
||||
{
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids });
|
||||
}
|
||||
if (ids.Any())
|
||||
{
|
||||
s.Where("umbracoNode.id in (@ids)", new { ids });
|
||||
}
|
||||
//we only want the newest ones with this method
|
||||
s.Where<DocumentDto>(x => x.Newest, SqlSyntax);
|
||||
return s;
|
||||
};
|
||||
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
//we only want the newest ones with this method
|
||||
sql.Where<DocumentDto>(x => x.Newest);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
return ProcessQuery(translate(sqlBaseFull), translate(sqlBaseIds));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContent> PerformGetByQuery(IQuery<IContent> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
Func<SqlTranslator<IContent>, Sql> translate = (translator) =>
|
||||
{
|
||||
return translator.Translate()
|
||||
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
};
|
||||
|
||||
var translatorFull = new SqlTranslator<IContent>(sqlBaseFull, query);
|
||||
var translatorIds = new SqlTranslator<IContent>(sqlBaseIds, query);
|
||||
|
||||
return ProcessQuery(translate(translatorFull), translate(translatorIds));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Queries
|
||||
|
||||
private readonly IQuery<IContent> _publishedQuery = Query<IContent>.Builder.Where(x => x.Published == true);
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<IContent>
|
||||
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
protected override Sql GetBaseQuery(BaseQueryType queryType)
|
||||
{
|
||||
var sqlx = string.Format("LEFT OUTER JOIN {0} {1} ON ({1}.{2}={0}.{2} AND {1}.{3}=1)",
|
||||
var sql = new Sql();
|
||||
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsDocument.nodeId" : "*"))
|
||||
.From<DocumentDto>(SqlSyntax)
|
||||
.InnerJoin<ContentVersionDto>(SqlSyntax)
|
||||
.On<DocumentDto, ContentVersionDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
|
||||
|
||||
if (queryType == BaseQueryType.Full)
|
||||
{
|
||||
//The only reason we apply this left outer join is to be able to pull back the DocumentPublishedReadOnlyDto
|
||||
//information with the entire data set, so basically this will get both the latest document and also it's published
|
||||
//version if it has one. When performing a count or when just retrieving Ids like in paging, this is unecessary
|
||||
//and causes huge performance overhead for the SQL server, especially when sorting the result.
|
||||
//To fix this perf overhead we'd need another index on :
|
||||
// CREATE NON CLUSTERED INDEX ON cmsDocument.node + cmsDocument.published
|
||||
|
||||
var sqlx = string.Format("LEFT OUTER JOIN {0} {1} ON ({1}.{2}={0}.{2} AND {1}.{3}=1)",
|
||||
SqlSyntax.GetQuotedTableName("cmsDocument"),
|
||||
SqlSyntax.GetQuotedTableName("cmsDocument2"),
|
||||
SqlSyntax.GetQuotedColumnName("nodeId"),
|
||||
SqlSyntax.GetQuotedColumnName("published"));
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select(isCount ? "COUNT(*)" : "*")
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<ContentVersionDto>()
|
||||
.On<DocumentDto, ContentVersionDto>(left => left.VersionId, right => right.VersionId)
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
|
||||
// cannot do this because PetaPoco does not know how to alias the table
|
||||
//.LeftOuterJoin<DocumentPublishedReadOnlyDto>()
|
||||
//.On<DocumentDto, DocumentPublishedReadOnlyDto>(left => left.NodeId, right => right.NodeId)
|
||||
// so have to rely on writing our own SQL
|
||||
.Append(sqlx/*, new { @published = true }*/)
|
||||
sql.Append(sqlx /*, new { @published = true }*/);
|
||||
}
|
||||
|
||||
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
|
||||
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
return "umbracoNode.id = @Id";
|
||||
@@ -179,20 +200,32 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// not bring much safety - so this reverts to updating each record individually,
|
||||
// and it may be slower in the end, but should be more resilient.
|
||||
|
||||
var baseId = 0;
|
||||
var contentTypeIdsA = contentTypeIds == null ? new int[0] : contentTypeIds.ToArray();
|
||||
|
||||
Func<int, Sql, Sql> translate = (bId, sql) =>
|
||||
{
|
||||
if (contentTypeIdsA.Length > 0)
|
||||
{
|
||||
sql.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
|
||||
}
|
||||
|
||||
sql
|
||||
.Where<NodeDto>(x => x.NodeId > bId && x.Trashed == false, SqlSyntax)
|
||||
.Where<DocumentDto>(x => x.Published, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
return sql;
|
||||
};
|
||||
|
||||
var baseId = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// get the next group of nodes
|
||||
var query = GetBaseQuery(false);
|
||||
if (contentTypeIdsA.Length > 0)
|
||||
query = query
|
||||
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
|
||||
query = query
|
||||
.Where<NodeDto>(x => x.NodeId > baseId && x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
|
||||
var sqlFull = translate(baseId, GetBaseQuery(BaseQueryType.Full));
|
||||
var sqlIds = translate(baseId, GetBaseQuery(BaseQueryType.Ids));
|
||||
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(sqlFull, groupSize), SqlSyntax.SelectTop(sqlIds, groupSize))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -218,17 +251,23 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public override IEnumerable<IContent> GetAllVersions(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
return ProcessQuery(sql, true);
|
||||
Func<Sql, Sql> translate = s =>
|
||||
{
|
||||
return s.Where(GetBaseWhereClause(), new {Id = id})
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
};
|
||||
|
||||
var sqlFull = translate(GetBaseQuery(BaseQueryType.Full));
|
||||
var sqlIds = translate(GetBaseQuery(BaseQueryType.Ids));
|
||||
|
||||
return ProcessQuery(sqlFull, sqlIds, true);
|
||||
}
|
||||
|
||||
public override IContent GetByVersion(Guid versionId)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql).FirstOrDefault();
|
||||
|
||||
@@ -244,10 +283,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = new Sql()
|
||||
.Select("*")
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
|
||||
.Where<ContentVersionDto>(x => x.VersionId == versionId)
|
||||
.Where<DocumentDto>(x => x.Newest != true);
|
||||
.From<DocumentDto>(SqlSyntax)
|
||||
.InnerJoin<ContentVersionDto>(SqlSyntax).On<ContentVersionDto, DocumentDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
|
||||
.Where<ContentVersionDto>(x => x.VersionId == versionId, SqlSyntax)
|
||||
.Where<DocumentDto>(x => x.Newest != true, SqlSyntax);
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto>(sql).FirstOrDefault();
|
||||
|
||||
if (dto == null) return;
|
||||
@@ -348,6 +387,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
nodeDto.ValidatePathWithException();
|
||||
Database.Update(nodeDto);
|
||||
|
||||
//Update entity with correct values
|
||||
@@ -485,6 +525,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//Updates the (base) node data - umbracoNode
|
||||
var nodeDto = dto.ContentVersionDto.ContentDto.NodeDto;
|
||||
nodeDto.ValidatePathWithException();
|
||||
var o = Database.Update(nodeDto);
|
||||
|
||||
//Only update this DTO if the contentType has actually changed
|
||||
@@ -620,21 +661,27 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public IEnumerable<IContent> GetByPublishedVersion(IQuery<IContent> query)
|
||||
{
|
||||
Func<SqlTranslator<IContent>, Sql> translate = t =>
|
||||
{
|
||||
return t.Translate()
|
||||
.Where<DocumentDto>(x => x.Published, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
};
|
||||
|
||||
// we WANT to return contents in top-down order, ie parents should come before children
|
||||
// ideal would be pure xml "document order" which can be achieved with:
|
||||
// ORDER BY substring(path, 1, len(path) - charindex(',', reverse(path))), sortOrder
|
||||
// but that's probably an overkill - sorting by level,sortOrder should be enough
|
||||
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.Where<DocumentDto>(x => x.Published)
|
||||
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
var sqlFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var translatorFull = new SqlTranslator<IContent>(sqlFull, query);
|
||||
var sqlIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
var translatorIds = new SqlTranslator<IContent>(sqlIds, query);
|
||||
|
||||
return ProcessQuery(sql, true);
|
||||
return ProcessQuery(translate(translatorFull), translate(translatorIds), true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
@@ -666,10 +713,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
parent.Attributes.Append(pIdAtt);
|
||||
xmlDoc.AppendChild(parent);
|
||||
|
||||
const string sql = @"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.xml, umbracoNode.level from umbracoNode
|
||||
//Ensure that only nodes that have published versions are selected
|
||||
var sql = string.Format(@"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.{0}, umbracoNode.{1} from umbracoNode
|
||||
inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type
|
||||
where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDocument.published = 1)
|
||||
order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
SqlSyntax.GetQuotedColumnName("xml"),
|
||||
SqlSyntax.GetQuotedColumnName("level"),
|
||||
SqlSyntax.GetQuotedColumnName("level"));
|
||||
|
||||
XmlElement last = null;
|
||||
|
||||
@@ -806,9 +857,9 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
|
||||
Func<Tuple<string, object[]>> filterCallback = () => new Tuple<string, object[]>(filterSql.SQL, filterSql.Arguments);
|
||||
|
||||
return GetPagedResultsByQuery<DocumentDto, Content>(query, pageIndex, pageSize, out totalRecords,
|
||||
return GetPagedResultsByQuery<DocumentDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsDocument", "nodeId"),
|
||||
sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull, sqlIds), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
|
||||
}
|
||||
@@ -839,16 +890,32 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
return base.GetDatabaseFieldNameForOrderBy(orderBy);
|
||||
}
|
||||
|
||||
private IEnumerable<IContent> ProcessQuery(Sql sql, bool withCache = false)
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The full SQL with the outer join to return all data required to create an IContent
|
||||
/// </param>
|
||||
/// <param name="sqlIds">
|
||||
/// The Id SQL without the outer join to just return all document ids - used to process the properties for the content item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, Sql sqlIds, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql);
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sqlFull);
|
||||
if (dtos.Count == 0) return Enumerable.Empty<IContent>();
|
||||
|
||||
var content = new IContent[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
var templateIds = new List<int>();
|
||||
|
||||
|
||||
//track the looked up content types, even though the content types are cached
|
||||
// they still need to be deep cloned out of the cache and we don't want to add
|
||||
// the overhead of deep cloning them on every item in this loop
|
||||
var contentTypes = new Dictionary<int, IContentType>();
|
||||
|
||||
for (var i = 0; i < dtos.Count; i++)
|
||||
{
|
||||
var dto = dtos[i];
|
||||
@@ -857,7 +924,8 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
if (withCache)
|
||||
{
|
||||
var cached = RuntimeCache.GetCacheItem<IContent>(GetCacheIdKey<IContent>(dto.NodeId));
|
||||
if (cached != null && cached.Published)
|
||||
//only use this cached version if the dto returned is also the publish version, they must match
|
||||
if (cached != null && cached.Published && dto.Published)
|
||||
{
|
||||
content[i] = cached;
|
||||
continue;
|
||||
@@ -866,9 +934,19 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
|
||||
// else, need to fetch from the database
|
||||
// content type repository is full-cache so OK to get each one independently
|
||||
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
content[i] = factory.BuildEntity(dto);
|
||||
|
||||
IContentType contentType;
|
||||
if (contentTypes.ContainsKey(dto.ContentVersionDto.ContentDto.ContentTypeId))
|
||||
{
|
||||
contentType = contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId];
|
||||
}
|
||||
else
|
||||
{
|
||||
contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId] = contentType;
|
||||
}
|
||||
|
||||
content[i] = ContentFactory.BuildEntity(dto, contentType);
|
||||
|
||||
// need template
|
||||
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
|
||||
@@ -889,7 +967,7 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(sql, defs);
|
||||
var propertyData = GetPropertyCollection(sqlIds, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
@@ -909,7 +987,7 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
((Entity) cc).ResetDirtyProperties(false);
|
||||
cc.ResetDirtyProperties(false);
|
||||
}
|
||||
|
||||
return content;
|
||||
@@ -926,8 +1004,7 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
{
|
||||
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
|
||||
|
||||
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var content = factory.BuildEntity(dto);
|
||||
var content = ContentFactory.BuildEntity(dto, contentType);
|
||||
|
||||
//Check if template id is set on DocumentDto, and get ITemplate if it is.
|
||||
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
|
||||
|
||||
@@ -62,17 +62,27 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<EntityContainer> PerformGetAll(params int[] ids)
|
||||
{
|
||||
//we need to batch these in groups of 2000 so we don't exceed the max 2100 limit
|
||||
return ids.InGroupsOf(2000).SelectMany(@group =>
|
||||
if (ids.Any())
|
||||
{
|
||||
//we need to batch these in groups of 2000 so we don't exceed the max 2100 limit
|
||||
return ids.InGroupsOf(2000).SelectMany(@group =>
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where("nodeObjectType=@umbracoObjectTypeId", new {umbracoObjectTypeId = NodeObjectTypeId})
|
||||
.Where(string.Format("{0} IN (@ids)", SqlSyntax.GetQuotedColumnName("id")), new {ids = @group});
|
||||
|
||||
sql.OrderBy<NodeDto>(x => x.Level, SqlSyntax);
|
||||
|
||||
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where("nodeObjectType=@umbracoObjectTypeId", new { umbracoObjectTypeId = NodeObjectTypeId })
|
||||
.Where(string.Format("{0} IN (@ids)", SqlSyntax.GetQuotedColumnName("id")), new { ids = @group });
|
||||
|
||||
.Where("nodeObjectType=@umbracoObjectTypeId", new {umbracoObjectTypeId = NodeObjectTypeId});
|
||||
sql.OrderBy<NodeDto>(x => x.Level, SqlSyntax);
|
||||
|
||||
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<EntityContainer> PerformGetByQuery(IQuery<EntityContainer> query)
|
||||
|
||||
@@ -96,5 +96,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IContent> filter = null);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -38,15 +38,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
IEnumerable<IMedia> GetPagedResultsByQuery(IQuery<IMedia> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, bool orderBySystemField, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged media descendants as XML by path
|
||||
/// </summary>
|
||||
/// <param name="path">Path starts with</param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of media items</returns>
|
||||
IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, out long totalRecords);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="content"></param>
|
||||
/// <param name="xml"></param>
|
||||
void AddOrUpdatePreviewXml(IMember content, Func<IMember, XElement> xml);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -67,5 +67,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="id">Id of the <see cref="TEntity"/> object to delete versions from</param>
|
||||
/// <param name="versionDate">Latest version date</param>
|
||||
void DeleteVersions(int id, DateTime versionDate);
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged content descendants as XML by path
|
||||
/// </summary>
|
||||
/// <param name="path">Path starts with</param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of content items</returns>
|
||||
IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, string[] orderBy, out long totalRecords);
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IMedia>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
}
|
||||
@@ -84,18 +84,23 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
#endregion
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<int,IMedia>
|
||||
|
||||
protected override Sql GetBaseQuery(BaseQueryType queryType)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsContentVersion.contentId" : "*"))
|
||||
.From<ContentVersionDto>(SqlSyntax)
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId, SqlSyntax)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(isCount ? "COUNT(*)" : "*")
|
||||
.From<ContentVersionDto>()
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
return sql;
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -148,6 +153,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var content = new IMedia[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
|
||||
//track the looked up content types, even though the content types are cached
|
||||
// they still need to be deep cloned out of the cache and we don't want to add
|
||||
// the overhead of deep cloning them on every item in this loop
|
||||
var contentTypes = new Dictionary<int, IMediaType>();
|
||||
|
||||
for (var i = 0; i < dtos.Count; i++)
|
||||
{
|
||||
var dto = dtos[i];
|
||||
@@ -165,9 +175,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
// else, need to fetch from the database
|
||||
// content type repository is full-cache so OK to get each one independently
|
||||
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
content[i] = factory.BuildEntity(dto);
|
||||
|
||||
IMediaType contentType;
|
||||
if (contentTypes.ContainsKey(dto.ContentDto.ContentTypeId))
|
||||
{
|
||||
contentType = contentTypes[dto.ContentDto.ContentTypeId];
|
||||
}
|
||||
else
|
||||
{
|
||||
contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
contentTypes[dto.ContentDto.ContentTypeId] = contentType;
|
||||
}
|
||||
|
||||
content[i] = MediaFactory.BuildEntity(dto, contentType);
|
||||
|
||||
// need properties
|
||||
defs.Add(new DocumentDefinition(
|
||||
@@ -195,7 +215,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
((Entity) cc).ResetDirtyProperties(false);
|
||||
cc.ResetDirtyProperties(false);
|
||||
}
|
||||
|
||||
return content;
|
||||
@@ -205,26 +225,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var mediaType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
var content = CreateMediaFromDto(dto, versionId, sql);
|
||||
|
||||
var factory = new MediaFactory(mediaType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
var properties = GetPropertyCollection(sql, new[] { new DocumentDefinition(dto.NodeId, dto.VersionId, media.UpdateDate, media.CreateDate, mediaType) });
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
((Entity)media).ResetDirtyProperties(false);
|
||||
return media;
|
||||
return content;
|
||||
}
|
||||
|
||||
public void RebuildXmlStructures(Func<IMedia, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null)
|
||||
@@ -245,7 +255,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
query = query
|
||||
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
|
||||
query = query
|
||||
.Where<NodeDto>(x => x.NodeId > baseId)
|
||||
.Where<NodeDto>(x => x.NodeId > baseId, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
@@ -324,6 +334,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
nodeDto.ValidatePathWithException();
|
||||
Database.Update(nodeDto);
|
||||
|
||||
//Update entity with correct values
|
||||
@@ -397,6 +408,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//Updates the (base) node data - umbracoNode
|
||||
var nodeDto = dto.ContentDto.NodeDto;
|
||||
nodeDto.ValidatePathWithException();
|
||||
var o = Database.Update(nodeDto);
|
||||
|
||||
//Only update this DTO if the contentType has actually changed
|
||||
@@ -493,37 +505,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
|
||||
}
|
||||
|
||||
return GetPagedResultsByQuery<ContentVersionDto, Models.Media>(query, pageIndex, pageSize, out totalRecords,
|
||||
return GetPagedResultsByQuery<ContentVersionDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsContentVersion", "contentId"),
|
||||
sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged media descendants as XML by path
|
||||
/// </summary>
|
||||
/// <param name="path">Path starts with</param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of media items</returns>
|
||||
public IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, out long totalRecords)
|
||||
{
|
||||
Sql query;
|
||||
if (path == "-1")
|
||||
{
|
||||
query = new Sql().Select("nodeId, xml").From("cmsContentXml").Where("nodeId IN (SELECT id FROM umbracoNode WHERE nodeObjectType = @0)", Guid.Parse(Constants.ObjectTypes.Media)).OrderBy("nodeId");
|
||||
}
|
||||
else
|
||||
{
|
||||
query = new Sql().Select("nodeId, xml").From("cmsContentXml").Where("nodeId IN (SELECT id FROM umbracoNode WHERE path LIKE @0)", path.EnsureEndsWith(",%")).OrderBy("nodeId");
|
||||
}
|
||||
var pagedResult = Database.Page<ContentXmlDto>(pageIndex+1, pageSize, query);
|
||||
totalRecords = pagedResult.TotalItems;
|
||||
return pagedResult.Items.Select(dto => XElement.Parse(dto.Xml));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
@@ -534,9 +522,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId, Sql docSql)
|
||||
{
|
||||
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
|
||||
|
||||
var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
var media = MediaFactory.BuildEntity(dto, contentType);
|
||||
|
||||
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
|
||||
|
||||
|
||||
@@ -107,24 +107,29 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<int,IMembershipUser>
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
protected override Sql GetBaseQuery(BaseQueryType queryType)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(isCount ? "COUNT(*)" : "*")
|
||||
.From<MemberDto>()
|
||||
.InnerJoin<ContentVersionDto>()
|
||||
.On<ContentVersionDto, MemberDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsMember.nodeId" : "*"))
|
||||
.From<MemberDto>(SqlSyntax)
|
||||
.InnerJoin<ContentVersionDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, MemberDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
//We're joining the type so we can do a query against the member type - not sure if this adds much overhead or not?
|
||||
// the execution plan says it doesn't so we'll go with that and in that case, it might be worth joining the content
|
||||
// types by default on the document and media repo's so we can query by content type there too.
|
||||
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
.InnerJoin<ContentTypeDto>(SqlSyntax)
|
||||
.On<ContentTypeDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.ContentTypeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -381,7 +386,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
return ProcessQuery(sql, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void RebuildXmlStructures(Func<IMember, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null)
|
||||
{
|
||||
@@ -617,9 +622,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
|
||||
}
|
||||
|
||||
return GetPagedResultsByQuery<MemberDto, Member>(query, pageIndex, pageSize, out totalRecords,
|
||||
return GetPagedResultsByQuery<MemberDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsMember", "nodeId"),
|
||||
sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +241,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
entity.Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//this means that the master template has been removed, so we need to reset the template's
|
||||
//path to be at the root
|
||||
entity.Path = string.Concat("-1,", entity.Id);
|
||||
}
|
||||
}
|
||||
|
||||
//Get TemplateDto from db to get the Primary key of the entity
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -25,8 +27,6 @@ using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
using SqlSyntax;
|
||||
|
||||
internal abstract class VersionableRepositoryBase<TId, TEntity> : PetaPocoRepositoryBase<TId, TEntity>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
@@ -137,6 +137,40 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged document descendants as XML by path
|
||||
/// </summary>
|
||||
/// <param name="path">Path starts with</param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of content items</returns>
|
||||
public virtual IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, string[] orderBy, out long totalRecords)
|
||||
{
|
||||
var query = new Sql().Select(string.Format("umbracoNode.id, cmsContentXml.{0}", SqlSyntax.GetQuotedColumnName("xml")))
|
||||
.From("umbracoNode")
|
||||
.InnerJoin("cmsContentXml").On("cmsContentXml.nodeId = umbracoNode.id");
|
||||
|
||||
if (path == "-1")
|
||||
{
|
||||
query.Where("umbracoNode.nodeObjectType = @type", new { type = NodeObjectTypeId });
|
||||
}
|
||||
else
|
||||
{
|
||||
query.Where(string.Format("umbracoNode.{0} LIKE (@0)", SqlSyntax.GetQuotedColumnName("path")), path.EnsureEndsWith(",%"));
|
||||
}
|
||||
|
||||
//each order by param needs to be in a bracket! see: https://github.com/toptensoftware/PetaPoco/issues/177
|
||||
query.OrderBy(orderBy == null
|
||||
? "(umbracoNode.id)"
|
||||
: string.Join(",", orderBy.Select(x => string.Format("({0})", SqlSyntax.GetQuotedColumnName(x)))));
|
||||
|
||||
var pagedResult = Database.Page<ContentXmlDto>(pageIndex + 1, pageSize, query);
|
||||
totalRecords = pagedResult.TotalItems;
|
||||
return pagedResult.Items.Select(dto => XElement.Parse(dto.Xml));
|
||||
}
|
||||
|
||||
public int CountDescendants(int parentId, string contentTypeAlias = null)
|
||||
{
|
||||
var pathMatch = parentId == -1
|
||||
@@ -348,12 +382,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
ON CustomPropData.CustomPropValContentId = umbracoNode.id
|
||||
", sortedInt, sortedDecimal, sortedDate, sortedString, nodeIdSelect.Item2, nodeIdSelect.Item1, versionQuery, sortedSql.Arguments.Length, newestQuery);
|
||||
|
||||
//insert this just above the first LEFT OUTER JOIN (for cmsDocument) or the last WHERE (everything else)
|
||||
string newSql;
|
||||
if (nodeIdSelect.Item1 == "cmsDocument")
|
||||
newSql = sortedSql.SQL.Insert(sortedSql.SQL.IndexOf("LEFT OUTER JOIN"), outerJoinTempTable);
|
||||
else
|
||||
newSql = sortedSql.SQL.Insert(sortedSql.SQL.LastIndexOf("WHERE"), outerJoinTempTable);
|
||||
//insert this just above the last WHERE
|
||||
string newSql = sortedSql.SQL.Insert(sortedSql.SQL.LastIndexOf("WHERE"), outerJoinTempTable);
|
||||
|
||||
var newArgs = sortedSql.Arguments.ToList();
|
||||
newArgs.Add(orderBy);
|
||||
@@ -370,11 +400,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
//no matter what we always MUST order the result also by umbracoNode.id to ensure that all records being ordered by are unique.
|
||||
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
|
||||
// is empty for many nodes)
|
||||
// see: http://issues.umbraco.org/issue/U4-8831
|
||||
sortedSql.OrderBy("umbracoNode.id");
|
||||
if (orderBySystemField && orderBy != "umbracoNode.id")
|
||||
{
|
||||
//no matter what we always MUST order the result also by umbracoNode.id to ensure that all records being ordered by are unique.
|
||||
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
|
||||
// is empty for many nodes)
|
||||
// see: http://issues.umbraco.org/issue/U4-8831
|
||||
sortedSql.OrderBy("umbracoNode.id");
|
||||
}
|
||||
|
||||
return sortedSql;
|
||||
|
||||
@@ -384,7 +417,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// A helper method for inheritors to get the paged results by query in a way that minimizes queries
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto">The type of the d.</typeparam>
|
||||
/// <typeparam name="TContentBase">The 'true' entity type (i.e. Content, Member, etc...)</typeparam>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="pageIndex">Index of the page.</param>
|
||||
/// <param name="pageSize">Size of the page.</param>
|
||||
@@ -397,34 +429,30 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="System.ArgumentNullException">orderBy</exception>
|
||||
protected IEnumerable<TEntity> GetPagedResultsByQuery<TDto, TContentBase>(IQuery<TEntity> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
protected IEnumerable<TEntity> GetPagedResultsByQuery<TDto>(IQuery<TEntity> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
Tuple<string, string> nodeIdSelect,
|
||||
Func<Sql, IEnumerable<TEntity>> processQuery,
|
||||
Func<Sql, Sql, IEnumerable<TEntity>> processQuery,
|
||||
string orderBy,
|
||||
Direction orderDirection,
|
||||
bool orderBySystemField,
|
||||
Func<Tuple<string, object[]>> defaultFilter = null)
|
||||
where TContentBase : class, IAggregateRoot, TEntity
|
||||
{
|
||||
if (orderBy == null) throw new ArgumentNullException("orderBy");
|
||||
|
||||
// Get base query
|
||||
var sqlBase = GetBaseQuery(false);
|
||||
// Get base query for returning IDs
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
// Get base query for returning all data
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
|
||||
if (query == null) query = new Query<TEntity>();
|
||||
var translator = new SqlTranslator<TEntity>(sqlBase, query);
|
||||
var sqlQuery = translator.Translate();
|
||||
|
||||
// Note we can't do multi-page for several DTOs like we can multi-fetch and are doing in PerformGetByQuery,
|
||||
// but actually given we are doing a Get on each one (again as in PerformGetByQuery), we only need the node Id.
|
||||
// So we'll modify the SQL.
|
||||
var sqlNodeIds = new Sql(
|
||||
sqlQuery.SQL.Replace("SELECT *", string.Format("SELECT {0}.{1}", nodeIdSelect.Item1, nodeIdSelect.Item2)),
|
||||
sqlQuery.Arguments);
|
||||
var translatorIds = new SqlTranslator<TEntity>(sqlBaseIds, query);
|
||||
var sqlQueryIds = translatorIds.Translate();
|
||||
var translatorFull = new SqlTranslator<TEntity>(sqlBaseFull, query);
|
||||
var sqlQueryFull = translatorFull.Translate();
|
||||
|
||||
//get sorted and filtered sql
|
||||
var sqlNodeIdsWithSort = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(sqlNodeIds, defaultFilter),
|
||||
GetFilteredSqlForPagedResults(sqlQueryIds, defaultFilter),
|
||||
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
|
||||
|
||||
// Get page of results and total count
|
||||
@@ -440,31 +468,25 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Crete the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = sqlNodeIdsWithSort.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
|
||||
//if this is for sql server, the sqlPage will start with a SELECT * but we don't want that, we only want to return the nodeId
|
||||
sqlStringPage = sqlStringPage
|
||||
.Replace("SELECT *",
|
||||
//This ensures we only take the field name of the node id select and not the table name - since the resulting select
|
||||
// will ony work with the field name.
|
||||
"SELECT " + nodeIdSelect.Item2);
|
||||
|
||||
//We need to make this an inner join on the paged query
|
||||
var splitQuery = sqlQuery.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None);
|
||||
var withInnerJoinSql = new Sql(splitQuery[0])
|
||||
//We need to make this FULL query an inner join on the paged ID query
|
||||
var splitQuery = sqlQueryFull.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None);
|
||||
var fullQueryWithPagedInnerJoin = new Sql(splitQuery[0])
|
||||
.Append("INNER JOIN (")
|
||||
//join the paged query with the paged query arguments
|
||||
.Append(sqlStringPage, args)
|
||||
.Append(") temp ")
|
||||
.Append(string.Format("ON {0}.{1} = temp.{1}", nodeIdSelect.Item1, nodeIdSelect.Item2))
|
||||
//add the original where clause back with the original arguments
|
||||
.Where(splitQuery[1], sqlQuery.Arguments);
|
||||
.Where(splitQuery[1], sqlQueryIds.Arguments);
|
||||
|
||||
//get sorted and filtered sql
|
||||
var fullQuery = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(withInnerJoinSql, defaultFilter),
|
||||
GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, defaultFilter),
|
||||
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
|
||||
return processQuery(fullQuery);
|
||||
|
||||
return processQuery(fullQuery, sqlNodeIdsWithSort);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -476,9 +498,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
|
||||
Sql docSql,
|
||||
IEnumerable<DocumentDefinition> documentDefs)
|
||||
IReadOnlyCollection<DocumentDefinition> documentDefs)
|
||||
{
|
||||
if (documentDefs.Any() == false) return new Dictionary<int, PropertyCollection>();
|
||||
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
|
||||
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
|
||||
// the statement to go get the property data for all of the items by using an inner join
|
||||
@@ -489,23 +511,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
var propSql = new Sql(@"SELECT cmsPropertyData.*
|
||||
FROM cmsPropertyData
|
||||
INNER JOIN cmsPropertyType
|
||||
ON cmsPropertyData.propertytypeid = cmsPropertyType.id
|
||||
INNER JOIN
|
||||
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
|
||||
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
|
||||
LEFT OUTER JOIN cmsDataTypePreValues
|
||||
ON cmsPropertyType.dataTypeId = cmsDataTypePreValues.datatypeNodeId", docSql.Arguments);
|
||||
|
||||
var allPropertyData = Database.Fetch<PropertyDataDto>(propSql);
|
||||
|
||||
//This is a lazy access call to get all prevalue data for the data types that make up all of these properties which we use
|
||||
// below if any property requires tag support
|
||||
var allPreValues = new Lazy<IEnumerable<DataTypePreValueDto>>(() =>
|
||||
{
|
||||
var preValsSql = new Sql(@"SELECT a.id, a.value, a.sortorder, a.alias, a.datatypeNodeId
|
||||
//This retrieves all pre-values for all data types that are referenced for all property types
|
||||
// that exist in the data set.
|
||||
//Benchmarks show that eagerly loading these so that we can lazily read the property data
|
||||
// below (with the use of Query intead of Fetch) go about 30% faster, so we'll eagerly load
|
||||
// this now since we cannot execute another reader inside of reading the property data.
|
||||
var preValsSql = new Sql(@"SELECT a.id, a.value, a.sortorder, a.alias, a.datatypeNodeId
|
||||
FROM cmsDataTypePreValues a
|
||||
WHERE EXISTS(
|
||||
SELECT DISTINCT b.id as preValIdInner
|
||||
@@ -517,25 +528,85 @@ WHERE EXISTS(
|
||||
ON cmsPropertyType.contentTypeId = docData.contentType
|
||||
WHERE a.id = b.id)", docSql.Arguments);
|
||||
|
||||
return Database.Fetch<DataTypePreValueDto>(preValsSql);
|
||||
});
|
||||
var allPreValues = Database.Fetch<DataTypePreValueDto>(preValsSql);
|
||||
|
||||
//It's Important with the sort order here! We require this to be sorted by node id,
|
||||
// this is required because this data set can be huge depending on the page size. Due
|
||||
// to it's size we need to be smart about iterating over the property values to build
|
||||
// the document. Before we used to use Linq to get the property data for a given content node
|
||||
// and perform a Distinct() call. This kills performance because that would mean if we had 7000 nodes
|
||||
// and on each iteration we will perform a lookup on potentially 100,000 property rows against the node
|
||||
// id which turns out to be a crazy amount of iterations. Instead we know it's sorted by this value we'll
|
||||
// keep an index stored of the rows being read so we never have to re-iterate the entire data set
|
||||
// on each document iteration.
|
||||
var propSql = new Sql(@"SELECT cmsPropertyData.*
|
||||
FROM cmsPropertyData
|
||||
INNER JOIN cmsPropertyType
|
||||
ON cmsPropertyData.propertytypeid = cmsPropertyType.id
|
||||
INNER JOIN
|
||||
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
|
||||
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
|
||||
ORDER BY contentNodeId, propertytypeid
|
||||
", docSql.Arguments);
|
||||
|
||||
//This does NOT fetch all data into memory in a list, this will read
|
||||
// over the records as a data reader, this is much better for performance and memory,
|
||||
// but it means that during the reading of this data set, nothing else can be read
|
||||
// from SQL server otherwise we'll get an exception.
|
||||
var allPropertyData = Database.Query<PropertyDataDto>(propSql);
|
||||
|
||||
var result = new Dictionary<int, PropertyCollection>();
|
||||
|
||||
var propertiesWithTagSupport = new Dictionary<string, SupportTagsAttribute>();
|
||||
//used to track the resolved composition property types per content type so we don't have to re-resolve (ToArray) the list every time
|
||||
var resolvedCompositionProperties = new Dictionary<int, PropertyType[]>();
|
||||
|
||||
//iterate each definition grouped by it's content type - this will mean less property type iterations while building
|
||||
// up the property collections
|
||||
foreach (var compositionGroup in documentDefs.GroupBy(x => x.Composition))
|
||||
//keep track of the current property data item being enumerated
|
||||
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
|
||||
|
||||
try
|
||||
{
|
||||
var compositionProperties = compositionGroup.Key.CompositionPropertyTypes.ToArray();
|
||||
|
||||
foreach (var def in compositionGroup)
|
||||
//This must be sorted by node id because this is how we are sorting the query to lookup property types above,
|
||||
// which allows us to more efficiently iterate over the large data set of property values
|
||||
foreach (var def in documentDefs.OrderBy(x => x.Id))
|
||||
{
|
||||
var propertyDataDtos = allPropertyData.Where(x => x.NodeId == def.Id).Distinct();
|
||||
//get the resolved proeprties from our local cache, or resolve them and put them in cache
|
||||
PropertyType[] compositionProperties;
|
||||
if (resolvedCompositionProperties.ContainsKey(def.Composition.Id))
|
||||
{
|
||||
compositionProperties = resolvedCompositionProperties[def.Composition.Id];
|
||||
}
|
||||
else
|
||||
{
|
||||
compositionProperties = def.Composition.CompositionPropertyTypes.ToArray();
|
||||
resolvedCompositionProperties[def.Composition.Id] = compositionProperties;
|
||||
}
|
||||
|
||||
var propertyFactory = new PropertyFactory(compositionProperties, def.Version, def.Id, def.CreateDate, def.VersionDate);
|
||||
var properties = propertyFactory.BuildEntity(propertyDataDtos.ToArray()).ToArray();
|
||||
var propertyDataDtos = new List<PropertyDataDto>();
|
||||
|
||||
//Check if there is a current enumerated item and check if we match and add it
|
||||
if (propertyDataSetEnumerator.Current != null)
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
|
||||
{
|
||||
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
|
||||
}
|
||||
}
|
||||
//Move to the next position, see if we match and add it, if not exit
|
||||
while (propertyDataSetEnumerator.MoveNext())
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
|
||||
{
|
||||
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
//the node id has changed so we need to exit the loop,
|
||||
//the enumerator position will be maintained
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var properties = PropertyFactory.BuildEntity(propertyDataDtos, compositionProperties, def.CreateDate, def.VersionDate).ToArray();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
@@ -552,7 +623,7 @@ WHERE EXISTS(
|
||||
propertiesWithTagSupport[property.PropertyType.PropertyEditorAlias] = tagSupport;
|
||||
|
||||
//this property has tags, so we need to extract them and for that we need the prevals which we've already looked up
|
||||
var preValData = allPreValues.Value.Where(x => x.DataTypeNodeId == property.PropertyType.DataTypeDefinitionId)
|
||||
var preValData = allPreValues.Where(x => x.DataTypeNodeId == property.PropertyType.DataTypeDefinitionId)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
@@ -575,8 +646,13 @@ WHERE EXISTS(
|
||||
result[def.Id] = new PropertyCollection(properties);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
propertyDataSetEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public class DocumentDefinition
|
||||
@@ -688,5 +764,12 @@ WHERE EXISTS(
|
||||
|
||||
return allsuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For Paging, repositories must support returning different query for the query type specified
|
||||
/// </summary>
|
||||
/// <param name="queryType"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Sql GetBaseQuery(BaseQueryType queryType);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
@@ -11,6 +12,7 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
@@ -58,7 +60,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Static Queries
|
||||
|
||||
private readonly IQuery<IContent> _notTrashedQuery = Query<IContent>.Builder.Where(x => x.Trashed == false);
|
||||
private IQuery<IContent> _notTrashedQuery;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -583,7 +585,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
[Obsolete("Use the overload with 'long' parameter types instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
public IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
long total;
|
||||
var result = GetPagedDescendants(id, Convert.ToInt64(pageIndex), pageSize, out total, orderBy, orderDirection, true, filter);
|
||||
@@ -602,7 +604,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="orderDirection">Direction to order by</param>
|
||||
/// <param name="filter">Search text filter</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filter);
|
||||
}
|
||||
@@ -714,7 +716,12 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public IEnumerable<IContent> GetDescendants(IContent content)
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
|
||||
//This is a check to ensure that the path is correct for this entity to avoid problems like: http://issues.umbraco.org/issue/U4-9336 due to data corruption
|
||||
if (content.ValidatePath() == false)
|
||||
throw new InvalidDataException(string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", content.Id, content.Path, content.ParentId));
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
var pathMatch = content.Path + ",";
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(pathMatch) && x.Id != content.Id);
|
||||
@@ -793,6 +800,12 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<IContent> GetAllPublished()
|
||||
{
|
||||
//create it once if it is needed (no need for locking here)
|
||||
if (_notTrashedQuery == null)
|
||||
{
|
||||
_notTrashedQuery = Query<IContent>.Builder.Where(x => x.Trashed == false);
|
||||
}
|
||||
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetByPublishedVersion(_notTrashedQuery);
|
||||
@@ -990,6 +1003,10 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
//Hack: this ensures that the entity's path is valid and if not it fixes/persists it
|
||||
//see: http://issues.umbraco.org/issue/U4-9336
|
||||
content.EnsureValidPath(Logger, entity => GetById(entity.ParentId), QuickUpdate);
|
||||
|
||||
var originalPath = content.Path;
|
||||
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
@@ -1677,16 +1694,16 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
public bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var asArray = items.ToArray();
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(items), this))
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(asArray), this))
|
||||
return false;
|
||||
}
|
||||
|
||||
var shouldBePublished = new List<IContent>();
|
||||
var shouldBeSaved = new List<IContent>();
|
||||
|
||||
var asArray = items.ToArray();
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -1747,6 +1764,31 @@ namespace Umbraco.Core.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged content descendants as XML by path
|
||||
/// </summary>
|
||||
/// <param name="path">Path starts with</param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of content items</returns>
|
||||
public IEnumerable<XElement> GetPagedXmlEntries(string path, long pageIndex, int pageSize, out long totalRecords)
|
||||
{
|
||||
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
|
||||
Mandate.ParameterCondition(pageSize > 0, "pageSize");
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize,
|
||||
//This order by is VERY important! This allows us to figure out what is implicitly not published, see ContentRepository.BuildXmlCache and
|
||||
// UmbracoContentIndexer.PerformIndexAll which uses the logic based on this sort order
|
||||
new[] {"level", "parentID", "sortOrder"},
|
||||
out totalRecords);
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
@@ -1806,6 +1848,23 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Hack: This is used to fix some data if an entity's properties are invalid/corrupt
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
private void QuickUpdate(IContent content)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (content.HasIdentity == false) throw new InvalidOperationException("Cannot update an entity without an Identity");
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(content);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
private void Audit(AuditType type, string message, int userId, int objectId)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -1913,6 +1972,10 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
//Hack: this ensures that the entity's path is valid and if not it fixes/persists it
|
||||
//see: http://issues.umbraco.org/issue/U4-9336
|
||||
content.EnsureValidPath(Logger, entity => GetById(entity.ParentId), QuickUpdate);
|
||||
|
||||
var result = new List<Attempt<PublishStatus>>();
|
||||
|
||||
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
|
||||
@@ -2154,6 +2217,11 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(content.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save content with empty name.");
|
||||
}
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
|
||||
@@ -719,8 +719,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user saving the ContentType</param>
|
||||
public void Save(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(contentType.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save content type with empty name.");
|
||||
}
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
|
||||
@@ -361,8 +361,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Id of the user issueing the save</param>
|
||||
public void Save(IDataTypeDefinition dataTypeDefinition, int userId = 0)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
|
||||
return;
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(dataTypeDefinition.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save datatype with empty name.");
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Static Queries
|
||||
|
||||
private readonly IQuery<IUmbracoEntity> _rootEntityQuery = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == -1);
|
||||
private IQuery<IUmbracoEntity> _rootEntityQuery;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -392,6 +392,12 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
public virtual IEnumerable<IUmbracoEntity> GetRootEntities(UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
//create it once if it is needed (no need for locking here)
|
||||
if (_rootEntityQuery == null)
|
||||
{
|
||||
_rootEntityQuery = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == -1);
|
||||
}
|
||||
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var repository = RepositoryFactory.CreateEntityRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -95,6 +96,19 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IContentService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all XML entries found in the cmsContentXml table based on the given path
|
||||
/// </summary>
|
||||
/// <param name="path">Path starts with</param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of content items</returns>
|
||||
/// <remarks>
|
||||
/// If -1 is passed, then this will return all content xml entries, otherwise will return all descendents from the path
|
||||
/// </remarks>
|
||||
IEnumerable<XElement> GetPagedXmlEntries(string path, long pageIndex, int pageSize, out long totalRecords);
|
||||
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
@@ -245,7 +259,7 @@ namespace Umbraco.Core.Services
|
||||
[Obsolete("Use the overload with 'long' parameter types instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
|
||||
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
|
||||
@@ -259,7 +273,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="filter">Search text filter</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Umbraco.Core.Services
|
||||
[Obsolete("Use the overload with 'long' parameter types instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
|
||||
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
|
||||
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="filter">Search text filter</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -13,6 +14,15 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IMemberService : IMembershipMemberService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all XML entries found in the cmsContentXml table
|
||||
/// </summary>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of content items</returns>
|
||||
IEnumerable<XElement> GetPagedXmlEntries(long pageIndex, int pageSize, out long totalRecords);
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds all xml content in the cmsContentXml table for all documents
|
||||
/// </summary>
|
||||
|
||||
@@ -142,19 +142,24 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user deleting the macro</param>
|
||||
public void Save(IMacro macro, int userId = 0)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMacro>(macro), this))
|
||||
return;
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMacroRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(macro);
|
||||
uow.Commit();
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMacro>(macro), this))
|
||||
return;
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMacro>(macro, false), this);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(macro.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save macro with empty name.");
|
||||
}
|
||||
|
||||
Audit(AuditType.Save, "Save Macro performed by user", userId, -1);
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMacroRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(macro);
|
||||
uow.Commit();
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMacro>(macro, false), this);
|
||||
}
|
||||
|
||||
Audit(AuditType.Save, "Save Macro performed by user", userId, -1);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
@@ -450,7 +451,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
[Obsolete("Use the overload with 'long' parameter types instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
public IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
long total;
|
||||
var result = GetPagedDescendants(id, Convert.ToInt64(pageIndex), pageSize, out total, orderBy, orderDirection, true, filter);
|
||||
@@ -469,7 +470,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="orderDirection">Direction to order by</param>
|
||||
/// <param name="filter">Search text filter</param>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
public IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filter);
|
||||
}
|
||||
@@ -527,6 +528,10 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An Enumerable flat list of <see cref="IMedia"/> objects</returns>
|
||||
public IEnumerable<IMedia> GetDescendants(IMedia media)
|
||||
{
|
||||
//This is a check to ensure that the path is correct for this entity to avoid problems like: http://issues.umbraco.org/issue/U4-9336 due to data corruption
|
||||
if (media.ValidatePath() == false)
|
||||
throw new InvalidDataException(string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", media.Id, media.Path, media.ParentId));
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
@@ -619,7 +624,7 @@ namespace Umbraco.Core.Services
|
||||
public IMedia GetMediaByPath(string mediaPath)
|
||||
{
|
||||
var umbracoFileValue = mediaPath;
|
||||
|
||||
|
||||
const string Pattern = ".*[_][0-9]+[x][0-9]+[.].*";
|
||||
var isResized = Regex.IsMatch(mediaPath, Pattern);
|
||||
|
||||
@@ -832,7 +837,11 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(media.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save media with empty name.");
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -998,56 +1007,63 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (media == null) throw new ArgumentNullException("media");
|
||||
|
||||
var originalPath = media.Path;
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
//Hack: this ensures that the entity's path is valid and if not it fixes/persists it
|
||||
//see: http://issues.umbraco.org/issue/U4-9336
|
||||
media.EnsureValidPath(Logger, entity => GetById(entity.ParentId), QuickUpdate);
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
{
|
||||
new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)
|
||||
};
|
||||
var originalPath = media.Path;
|
||||
|
||||
//Find Descendants, which will be moved to the recycle bin along with the parent/grandparent.
|
||||
var descendants = GetDescendants(media).OrderBy(x => x.Level).ToList();
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
//TODO: This should be part of the repo!
|
||||
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = media.Id });
|
||||
|
||||
media.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
|
||||
repository.AddOrUpdate(media);
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
{
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = descendant.Id });
|
||||
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
|
||||
moveInfo.Add(new MoveEventInfo<IMedia>(descendant, descendant.Path, descendant.ParentId));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
{
|
||||
new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)
|
||||
};
|
||||
|
||||
//Find Descendants, which will be moved to the recycle bin along with the parent/grandparent.
|
||||
var descendants = GetDescendants(media).OrderBy(x => x.Level).ToList();
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
//TODO: This should be part of the repo!
|
||||
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = media.Id });
|
||||
|
||||
media.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
|
||||
repository.AddOrUpdate(media);
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = descendant.Id });
|
||||
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
|
||||
moveInfo.Add(new MoveEventInfo<IMedia>(descendant, descendant.Path, descendant.ParentId));
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Trashed.RaiseEvent(
|
||||
new MoveEventArgs<IMedia>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
Trashed.RaiseEvent(
|
||||
new MoveEventArgs<IMedia>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1064,8 +1080,6 @@ namespace Umbraco.Core.Services
|
||||
((IMediaServiceOperations)this).Delete(media, userId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes versions from an <see cref="IMedia"/> object prior to a specific date.
|
||||
/// This method will never delete the latest version of a content item.
|
||||
@@ -1154,7 +1168,6 @@ namespace Umbraco.Core.Services
|
||||
public bool Sort(IEnumerable<IMedia> items, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var asArray = items.ToArray();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMedia>(asArray), this))
|
||||
@@ -1215,7 +1228,7 @@ namespace Umbraco.Core.Services
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, out totalRecords);
|
||||
var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, null, out totalRecords);
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -1316,6 +1329,23 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hack: This is used to fix some data if an entity's properties are invalid/corrupt
|
||||
/// </summary>
|
||||
/// <param name="media"></param>
|
||||
private void QuickUpdate(IMedia media)
|
||||
{
|
||||
if (media == null) throw new ArgumentNullException("media");
|
||||
if (media.HasIdentity == false) throw new InvalidOperationException("Cannot update an entity without an Identity");
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(media);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -612,6 +612,26 @@ namespace Umbraco.Core.Services
|
||||
Audit(AuditType.Publish, "MemberService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged member descendants as XML by path
|
||||
/// </summary>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records the query would return without paging</param>
|
||||
/// <returns>A paged enumerable of XML entries of member items</returns>
|
||||
public IEnumerable<XElement> GetPagedXmlEntries(long pageIndex, int pageSize, out long totalRecords)
|
||||
{
|
||||
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
|
||||
Mandate.ParameterCondition(pageSize > 0, "pageSize");
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
var contents = repository.GetPagedXmlEntriesByPath("-1", pageIndex, pageSize, null, out totalRecords);
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMembershipMemberService Implementation
|
||||
@@ -978,6 +998,11 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entity.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save member with empty name.");
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
|
||||
@@ -78,6 +78,11 @@ namespace Umbraco.Core.Services
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(memberType), this))
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(memberType.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save MemberType with empty name.");
|
||||
}
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
|
||||
@@ -125,6 +125,11 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (userType == null) throw new ArgumentNullException("userType");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
throw new ArgumentException("Cannot create user with empty username.");
|
||||
}
|
||||
|
||||
//TODO: PUT lock here!!
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -312,6 +317,15 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entity.Username))
|
||||
{
|
||||
throw new ArgumentException("Cannot save user with empty username.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(entity.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save user with empty name.");
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateUserRepository(uow))
|
||||
{
|
||||
@@ -353,6 +367,14 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
foreach (var member in entities)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(member.Username))
|
||||
{
|
||||
throw new ArgumentException("Cannot save user with empty username.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(member.Name))
|
||||
{
|
||||
throw new ArgumentException("Cannot save user with empty name.");
|
||||
}
|
||||
repository.AddOrUpdate(member);
|
||||
}
|
||||
//commit the whole lot in one go
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
@@ -39,67 +39,54 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib">
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.4.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.4.5.0\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="ImageProcessor, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.1\lib\net45\ImageProcessor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\log4net-mediumtrust.2.0.0\lib\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Owin, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security">
|
||||
<Reference Include="Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.Cookies, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.OAuth, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Reference Include="MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MySql.Data.6.9.8\lib\net45\MySql.Data.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Semver">
|
||||
<Reference Include="Semver, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\semver.1.1.2\lib\net45\Semver.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
@@ -107,11 +94,9 @@
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data.Entity" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
@@ -296,6 +281,7 @@
|
||||
<Compile Include="Configuration\UmbracoSettings\ServerCollection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\ServerElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\TemplatesElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\UmbracoConfigurationElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\UmbracoSettingsSection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\UrlReplacingElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\UserProviderElement.cs" />
|
||||
@@ -480,6 +466,7 @@
|
||||
<Compile Include="Persistence\RecordPersistenceType.cs" />
|
||||
<Compile Include="Persistence\Relators\AccessRulesRelator.cs" />
|
||||
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\BaseQueryType.cs" />
|
||||
<Compile Include="Persistence\Repositories\EntityContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DomainRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ExternalLoginRepository.cs" />
|
||||
@@ -1440,9 +1427,7 @@
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="FileResources\BlockingWeb.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\umbraco.interfaces\umbraco.interfaces.csproj">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.4.5.0" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
|
||||
<package id="ImageProcessor" version="2.5.1" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
|
||||
@@ -15,6 +15,6 @@
|
||||
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
<package id="semver" version="1.1.2" targetFramework="net45" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net4" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
/// <summary>
|
||||
/// Want to check what is faster OfType or Cast when a enurable all has the same items
|
||||
/// </summary>
|
||||
[Config(typeof(Config))]
|
||||
public class LinqCastBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
|
||||
public LinqCastBenchmarks()
|
||||
{
|
||||
_array = new List<object>();
|
||||
_array.AddRange(Enumerable.Range(0, 10000).Select(x => x.ToString()));
|
||||
}
|
||||
|
||||
private readonly List<object> _array;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public void OfType()
|
||||
{
|
||||
foreach (var i in _array.OfType<string>())
|
||||
{
|
||||
var a = i;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark()]
|
||||
public void Cast()
|
||||
{
|
||||
foreach (var i in _array.Cast<string>())
|
||||
{
|
||||
var a = i;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark()]
|
||||
public void ExplicitCast()
|
||||
{
|
||||
foreach (var i in _array)
|
||||
{
|
||||
var a = (string)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,14 @@ namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
var switcher = new BenchmarkSwitcher(new[]
|
||||
{
|
||||
var type = Assembly.GetExecutingAssembly().GetType("Umbraco.Tests.Benchmarks." +args[0]);
|
||||
if (type == null)
|
||||
{
|
||||
Console.WriteLine("Unknown benchmark.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var summary = BenchmarkRunner.Run(type);
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("?");
|
||||
}
|
||||
typeof(BulkInsertBenchmarks),
|
||||
typeof(ModelToSqlExpressionHelperBenchmarks),
|
||||
typeof(XmlBenchmarks),
|
||||
typeof(LinqCastBenchmarks)
|
||||
});
|
||||
switcher.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,31 +39,24 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="BenchmarkDotNet, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Core, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Diagnostics.Windows, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.1.37.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
@@ -73,20 +66,16 @@
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
@@ -96,6 +85,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="LinqCastBenchmarks.cs" />
|
||||
<Compile Include="ModelToSqlExpressionHelperBenchmarks.cs" />
|
||||
<Compile Include="BulkInsertBenchmarks.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
@@ -106,10 +96,6 @@
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
<Project>{31785bc3-256c-4613-b2f5-a1b0bdded8c1}</Project>
|
||||
@@ -120,7 +106,22 @@
|
||||
<Name>Umbraco.Tests</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
if not exist "$(TargetDir)x86" md "$(TargetDir)x86"
|
||||
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8854.1\NativeBinaries\x86\*.*" "$(TargetDir)x86"
|
||||
if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64"
|
||||
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8854.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /I /C /D
|
||||
xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets" Condition="Exists('..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
@@ -128,14 +129,6 @@
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets'))" />
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /I /C /D
|
||||
xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Tests.Models
|
||||
@@ -9,6 +12,132 @@ namespace Umbraco.Tests.Models
|
||||
[TestFixture]
|
||||
public class UmbracoEntityTests
|
||||
{
|
||||
[Test]
|
||||
public void Validate_Path()
|
||||
{
|
||||
var entity = new UmbracoEntity();
|
||||
|
||||
//it's empty with no id so we need to allow it
|
||||
Assert.IsTrue(entity.ValidatePath());
|
||||
|
||||
entity.Id = 1234;
|
||||
|
||||
//it has an id but no path, so we can't allow it
|
||||
Assert.IsFalse(entity.ValidatePath());
|
||||
|
||||
entity.Path = "-1";
|
||||
|
||||
//invalid path
|
||||
Assert.IsFalse(entity.ValidatePath());
|
||||
|
||||
entity.Path = string.Concat("-1,", entity.Id);
|
||||
|
||||
//valid path
|
||||
Assert.IsTrue(entity.ValidatePath());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Path_Throws_Without_Id()
|
||||
{
|
||||
var entity = new UmbracoEntity();
|
||||
|
||||
//no id assigned
|
||||
Assert.Throws<InvalidOperationException>(() => entity.EnsureValidPath(Mock.Of<ILogger>(), umbracoEntity => new UmbracoEntity(), umbracoEntity => { }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Path_Throws_Without_Parent()
|
||||
{
|
||||
var entity = new UmbracoEntity {Id = 1234};
|
||||
|
||||
//no parent found
|
||||
Assert.Throws<NullReferenceException>(() => entity.EnsureValidPath(Mock.Of<ILogger>(), umbracoEntity => null, umbracoEntity => { }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Path_Entity_At_Root()
|
||||
{
|
||||
var entity = new UmbracoEntity
|
||||
{
|
||||
Id = 1234,
|
||||
ParentId = -1
|
||||
};
|
||||
|
||||
|
||||
entity.EnsureValidPath(Mock.Of<ILogger>(), umbracoEntity => null, umbracoEntity => { });
|
||||
|
||||
//works because it's under the root
|
||||
Assert.AreEqual("-1,1234", entity.Path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Path_Entity_Valid_Parent()
|
||||
{
|
||||
var entity = new UmbracoEntity
|
||||
{
|
||||
Id = 1234,
|
||||
ParentId = 888
|
||||
};
|
||||
|
||||
entity.EnsureValidPath(Mock.Of<ILogger>(), umbracoEntity => umbracoEntity.ParentId == 888 ? new UmbracoEntity{Id = 888, Path = "-1,888"} : null, umbracoEntity => { });
|
||||
|
||||
//works because the parent was found
|
||||
Assert.AreEqual("-1,888,1234", entity.Path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Path_Entity_Valid_Recursive_Parent()
|
||||
{
|
||||
var parentA = new UmbracoEntity
|
||||
{
|
||||
Id = 999,
|
||||
ParentId = -1
|
||||
};
|
||||
|
||||
var parentB = new UmbracoEntity
|
||||
{
|
||||
Id = 888,
|
||||
ParentId = 999
|
||||
};
|
||||
|
||||
var parentC = new UmbracoEntity
|
||||
{
|
||||
Id = 777,
|
||||
ParentId = 888
|
||||
};
|
||||
|
||||
var entity = new UmbracoEntity
|
||||
{
|
||||
Id = 1234,
|
||||
ParentId = 777
|
||||
};
|
||||
|
||||
Func<IUmbracoEntity, IUmbracoEntity> getParent = umbracoEntity =>
|
||||
{
|
||||
switch (umbracoEntity.ParentId)
|
||||
{
|
||||
case 999:
|
||||
return parentA;
|
||||
case 888:
|
||||
return parentB;
|
||||
case 777:
|
||||
return parentC;
|
||||
case 1234:
|
||||
return entity;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
//this will recursively fix all paths
|
||||
entity.EnsureValidPath(Mock.Of<ILogger>(), getParent, umbracoEntity => { });
|
||||
|
||||
Assert.AreEqual("-1,999", parentA.Path);
|
||||
Assert.AreEqual("-1,999,888", parentB.Path);
|
||||
Assert.AreEqual("-1,999,888,777", parentC.Path);
|
||||
Assert.AreEqual("-1,999,888,777,1234", entity.Path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UmbracoEntity_Can_Be_Initialized_From_Dynamic()
|
||||
{
|
||||
|
||||
@@ -172,6 +172,38 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_All_Containers()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
EntityContainer container1, container2, container3;
|
||||
using (var containerRepository = CreateContainerRepository(unitOfWork, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
container1 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid) { Name = "container1" };
|
||||
containerRepository.AddOrUpdate(container1);
|
||||
container2 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid) { Name = "container2" };
|
||||
containerRepository.AddOrUpdate(container2);
|
||||
container3 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid) { Name = "container3" };
|
||||
containerRepository.AddOrUpdate(container3);
|
||||
unitOfWork.Commit();
|
||||
Assert.That(container1.Id, Is.GreaterThan(0));
|
||||
Assert.That(container2.Id, Is.GreaterThan(0));
|
||||
Assert.That(container3.Id, Is.GreaterThan(0));
|
||||
}
|
||||
using (var containerRepository = CreateContainerRepository(unitOfWork, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
var found1 = containerRepository.Get(container1.Id);
|
||||
Assert.IsNotNull(found1);
|
||||
var found2 = containerRepository.Get(container2.Id);
|
||||
Assert.IsNotNull(found2);
|
||||
var found3 = containerRepository.Get(container3.Id);
|
||||
Assert.IsNotNull(found3);
|
||||
var allContainers = containerRepository.GetAll();
|
||||
Assert.AreEqual(3, allContainers.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Container()
|
||||
{
|
||||
|
||||
@@ -707,6 +707,35 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Path_Is_Set_Correctly_On_Update_With_Master_Template_Removal()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var parent = new Template("parent", "parent");
|
||||
var child1 = new Template("child1", "child1");
|
||||
|
||||
child1.MasterTemplateAlias = parent.Alias;
|
||||
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child1);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//Act
|
||||
child1.SetMasterTemplate(null);
|
||||
repository.AddOrUpdate(child1);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(string.Format("-1,{0}", child1.Id), child1.Path);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Lucene.Net.Analysis.Standard;
|
||||
using Lucene.Net.Documents;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.Store;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@@ -31,12 +33,15 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Ensure_Children_Are_Sorted()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var result = searcher.Search(searcher.CreateSearchCriteria().Id(1111).Compile());
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(1, result.TotalItemCount);
|
||||
@@ -60,12 +65,15 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Ensure_Result_Has_All_Values()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var result = searcher.Search(searcher.CreateSearchCriteria().Id(1111).Compile());
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(1, result.TotalItemCount);
|
||||
|
||||
@@ -27,6 +27,7 @@ using UmbracoExamine;
|
||||
using UmbracoExamine.DataServices;
|
||||
using umbraco.BusinessLogic;
|
||||
using System.Linq;
|
||||
using Lucene.Net.Index;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
@@ -106,11 +107,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Ensure_Children_Sorted_With_Examine()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
@@ -135,11 +139,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Do_Not_Find_In_Recycle_Bin()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
@@ -175,11 +182,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Children_With_Examine()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
@@ -197,11 +207,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Descendants_With_Examine()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
@@ -219,11 +232,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void DescendantsOrSelf_With_Examine()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
@@ -241,12 +257,15 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void Ancestors_With_Examine()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
|
||||
@@ -260,12 +279,15 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void AncestorsOrSelf_With_Examine()
|
||||
{
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
|
||||
indexer.RebuildIndex();
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
|
||||
|
||||
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Routing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This checks that when we retrieve a NiceUrl for multiple items that there are no issues with cache overlap
|
||||
/// This checks that when we retrieve a NiceUrl for multiple items that there are no issues with cache overlap
|
||||
/// and that they are all cached correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
@@ -71,25 +71,19 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
var cache = routingContext.UmbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
|
||||
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual(8, cachedRoutes.Count);
|
||||
Assert.AreEqual(8, cachedRoutes.Count);
|
||||
|
||||
foreach (var sample in samples)
|
||||
{
|
||||
Assert.IsTrue(cachedRoutes.ContainsKey(sample.Key));
|
||||
Assert.AreEqual(sample.Value, cachedRoutes[sample.Key]);
|
||||
}
|
||||
foreach (var sample in samples)
|
||||
{
|
||||
Assert.IsTrue(cachedRoutes.ContainsKey(sample.Key));
|
||||
Assert.AreEqual(sample.Value, cachedRoutes[sample.Key]);
|
||||
}
|
||||
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(8, cachedIds.Count);
|
||||
|
||||
foreach (var sample in samples)
|
||||
{
|
||||
var key = sample.Value;
|
||||
Assert.IsTrue(cachedIds.ContainsKey(key));
|
||||
Assert.AreEqual(sample.Key, cachedIds[key]);
|
||||
}
|
||||
}
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(0, cachedIds.Count);
|
||||
}
|
||||
|
||||
// test hideTopLevelNodeFromPath false
|
||||
[TestCase(1046, "/home/")]
|
||||
@@ -147,10 +141,10 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
var routingContext = GetRoutingContext("http://example.com/test", 1111, umbracoSettings: _umbracoSettings);
|
||||
|
||||
|
||||
|
||||
|
||||
Assert.AreEqual("/home/sub1/custom-sub-1/", routingContext.UrlProvider.GetUrl(1177));
|
||||
|
||||
|
||||
requestMock.Setup(x => x.UseDomainPrefixes).Returns(true);
|
||||
Assert.AreEqual("http://example.com/home/sub1/custom-sub-1/", routingContext.UrlProvider.GetUrl(1177));
|
||||
|
||||
@@ -173,14 +167,14 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
Assert.AreEqual("#", routingContext.UrlProvider.GetUrl(999999));
|
||||
|
||||
requestMock.Setup(x => x.UseDomainPrefixes).Returns(true);
|
||||
|
||||
requestMock.Setup(x => x.UseDomainPrefixes).Returns(true);
|
||||
|
||||
Assert.AreEqual("#", routingContext.UrlProvider.GetUrl(999999));
|
||||
|
||||
requestMock.Setup(x => x.UseDomainPrefixes).Returns(false);
|
||||
|
||||
routingContext.UrlProvider.Mode = UrlProviderMode.Absolute;
|
||||
|
||||
|
||||
Assert.AreEqual("#", routingContext.UrlProvider.GetUrl(999999));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Routing
|
||||
{
|
||||
// purpose: test the values returned by PublishedContentCache.GetRouteById
|
||||
// and .GetByRoute (no caching at all, just routing nice urls) including all
|
||||
// the quirks due to hideTopLevelFromPath and backward compatibility.
|
||||
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerFixture)]
|
||||
[TestFixture]
|
||||
public class NiceUrlRoutesTests : BaseRoutingTest
|
||||
{
|
||||
#region Test Setup
|
||||
|
||||
protected override void FreezeResolution()
|
||||
{
|
||||
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
|
||||
|
||||
base.FreezeResolution();
|
||||
}
|
||||
|
||||
private IUmbracoSettingsSection _umbracoSettings;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
//generate new mock settings and assign so we can configure in individual tests
|
||||
_umbracoSettings = SettingsForTests.GenerateMockSettings();
|
||||
SettingsForTests.ConfigureSettings(_umbracoSettings);
|
||||
}
|
||||
|
||||
protected override string GetXmlContent(int templateId)
|
||||
{
|
||||
return @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<!DOCTYPE root[
|
||||
<!ELEMENT Doc ANY>
|
||||
<!ATTLIST Doc id ID #REQUIRED>
|
||||
]>
|
||||
<root id=""-1"">
|
||||
<Doc id=""1000"" parentID=""-1"" level=""1"" path=""-1,1000"" nodeName=""A"" urlName=""a"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
<Doc id=""1001"" parentID=""1000"" level=""2"" path=""-1,1000,1001"" nodeName=""B"" urlName=""b"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
<Doc id=""1002"" parentID=""1001"" level=""3"" path=""-1,1000,1001,1002"" nodeName=""C"" urlName=""c"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
<Doc id=""1003"" parentID=""1002"" level=""4"" path=""-1,1000,1001,1002,1003"" nodeName=""D"" urlName=""d"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
</Doc>
|
||||
</Doc>
|
||||
</Doc>
|
||||
</Doc>
|
||||
<Doc id=""2000"" parentID=""-1"" level=""1"" path=""-1,2000"" nodeName=""X"" urlName=""x"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
<Doc id=""2001"" parentID=""2000"" level=""2"" path=""-1,2000,2001"" nodeName=""Y"" urlName=""y"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
<Doc id=""2002"" parentID=""2001"" level=""3"" path=""-1,2000,2001,2002"" nodeName=""Z"" urlName=""z"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
</Doc>
|
||||
</Doc>
|
||||
<Doc id=""2003"" parentID=""2000"" level=""2"" path=""-1,2000,2003"" nodeName=""A"" urlName=""a"" sortOrder=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
</Doc>
|
||||
<Doc id=""2004"" parentID=""2000"" level=""2"" path=""-1,2000,2004"" nodeName=""B"" urlName=""b"" sortOrder=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
<Doc id=""2005"" parentID=""2004"" level=""3"" path=""-1,2000,2004,2005"" nodeName=""C"" urlName=""c"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
</Doc>
|
||||
<Doc id=""2006"" parentID=""2004"" level=""3"" path=""-1,2000,2004,2006"" nodeName=""E"" urlName=""e"" sortOrder=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" writerName=""admin"" creatorName=""admin"" isDoc="""">
|
||||
</Doc>
|
||||
</Doc>
|
||||
</Doc>
|
||||
</root>";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/*
|
||||
* Just so it's documented somewhere, as of jan. 2017, routes obey the following pseudo-code:
|
||||
|
||||
GetByRoute(route, hide = null):
|
||||
|
||||
route is "[id]/[path]"
|
||||
|
||||
hide = hide ?? global.hide
|
||||
|
||||
root = id ? node(id) : document
|
||||
|
||||
content = cached(route) ?? DetermineIdByRoute(route, hide)
|
||||
|
||||
# route is "1234/path/to/content", finds "content"
|
||||
# but if there is domain 5678 on "to", the *true* route of "content" is "5678/content"
|
||||
# so although the route does match, we don't cache it
|
||||
# there are not other reason not to cache it
|
||||
|
||||
if content and no domain between root and content:
|
||||
cache route (as trusted)
|
||||
|
||||
return content
|
||||
|
||||
|
||||
DetermineIdByRoute(route, hide):
|
||||
|
||||
route is "[id]/[path]"
|
||||
|
||||
try return NavigateRoute(id ?? 0, path, hide:hide)
|
||||
return null
|
||||
|
||||
|
||||
NavigateRoute(id, path, hide):
|
||||
|
||||
if path:
|
||||
if id:
|
||||
start = node(id)
|
||||
else:
|
||||
start = document
|
||||
|
||||
# 'navigate ... from ...' uses lowest sortOrder in case of collision
|
||||
|
||||
if hide and ![id]:
|
||||
# if hiding, then for "/foo" we want to look for "/[any]/foo"
|
||||
for each child of start:
|
||||
try return navigate path from child
|
||||
|
||||
# but if it fails, we also want to try "/foo"
|
||||
# fail now if more than one part eg "/foo/bar"
|
||||
if path is "/[any]/...":
|
||||
fail
|
||||
|
||||
try return navigate path from start
|
||||
|
||||
else:
|
||||
if id:
|
||||
return node(id)
|
||||
else:
|
||||
return root node with lowest sortOrder
|
||||
|
||||
|
||||
GetRouteById(id):
|
||||
|
||||
|
||||
route = cached(id)
|
||||
if route:
|
||||
return route
|
||||
|
||||
# never cache the route, it may be colliding
|
||||
|
||||
route = DetermineRouteById(id)
|
||||
if route:
|
||||
cache route (as not trusted)
|
||||
|
||||
return route
|
||||
|
||||
|
||||
|
||||
DetermineRouteById(id):
|
||||
|
||||
|
||||
node = node(id)
|
||||
|
||||
walk up from node to domain or root, assemble parts = url segments
|
||||
|
||||
if !domain and global.hide:
|
||||
if id.parent:
|
||||
# got /top/[path]content, can remove /top
|
||||
remove top part
|
||||
else:
|
||||
# got /content, should remove only if it is the
|
||||
# node with lowest sort order
|
||||
root = root node with lowest sortOrder
|
||||
if root == node:
|
||||
remove top part
|
||||
|
||||
compose path from parts
|
||||
route = assemble "[domain.id]/[path]"
|
||||
return route
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* The Xml structure for the following tests is:
|
||||
*
|
||||
* root
|
||||
* A 1000
|
||||
* B 1001
|
||||
* C 1002
|
||||
* D 1003
|
||||
* X 2000
|
||||
* Y 2001
|
||||
* Z 2002
|
||||
* A 2003
|
||||
* B 2004
|
||||
* C 2005
|
||||
* E 2006
|
||||
*
|
||||
*/
|
||||
|
||||
[TestCase(1000, false, "/a")]
|
||||
[TestCase(1001, false, "/a/b")]
|
||||
[TestCase(1002, false, "/a/b/c")]
|
||||
[TestCase(1003, false, "/a/b/c/d")]
|
||||
[TestCase(2000, false, "/x")]
|
||||
[TestCase(2001, false, "/x/y")]
|
||||
[TestCase(2002, false, "/x/y/z")]
|
||||
[TestCase(2003, false, "/x/a")]
|
||||
[TestCase(2004, false, "/x/b")]
|
||||
[TestCase(2005, false, "/x/b/c")]
|
||||
[TestCase(2006, false, "/x/b/e")]
|
||||
[TestCase(1000, true, "/")]
|
||||
[TestCase(1001, true, "/b")]
|
||||
[TestCase(1002, true, "/b/c")]
|
||||
[TestCase(1003, true, "/b/c/d")]
|
||||
[TestCase(2000, true, "/x")]
|
||||
[TestCase(2001, true, "/y")]
|
||||
[TestCase(2002, true, "/y/z")]
|
||||
[TestCase(2003, true, "/a")]
|
||||
[TestCase(2004, true, "/b")] // collision!
|
||||
[TestCase(2005, true, "/b/c")] // collision!
|
||||
[TestCase(2006, true, "/b/e")] // risky!
|
||||
public void GetRouteById(int id, bool hide, string expected)
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("/test", 0);
|
||||
var cache = umbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
|
||||
|
||||
SettingsForTests.HideTopLevelNodeFromPath = hide;
|
||||
|
||||
const bool preview = true; // make sure we don't cache
|
||||
var route = cache.GetRouteById(umbracoContext, preview, id);
|
||||
Assert.AreEqual(expected, route);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetRouteByIdCache()
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("/test", 0);
|
||||
var cache = umbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
|
||||
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false;
|
||||
|
||||
// make sure we cache
|
||||
PublishedContentCache.UnitTesting = false;
|
||||
const bool preview = false;
|
||||
|
||||
var route = cache.GetRouteById(umbracoContext, preview, 1000);
|
||||
Assert.AreEqual("/a", route);
|
||||
|
||||
// GetRouteById registers a non-trusted route, which is cached for
|
||||
// id -> route queries (fast GetUrl) but *not* for route -> id
|
||||
// queries (safe inbound routing)
|
||||
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual(1, cachedRoutes.Count);
|
||||
Assert.IsTrue(cachedRoutes.ContainsKey(1000));
|
||||
Assert.AreEqual("/a", cachedRoutes[1000]);
|
||||
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(0, cachedIds.Count);
|
||||
}
|
||||
|
||||
[TestCase("/", false, 1000)]
|
||||
[TestCase("/a", false, 1000)] // yes!
|
||||
[TestCase("/a/b", false, 1001)]
|
||||
[TestCase("/a/b/c", false, 1002)]
|
||||
[TestCase("/a/b/c/d", false, 1003)]
|
||||
[TestCase("/x", false, 2000)]
|
||||
[TestCase("/", true, 1000)]
|
||||
[TestCase("/a", true, 2003)]
|
||||
[TestCase("/a/b", true, -1)]
|
||||
[TestCase("/x", true, 2000)] // oops!
|
||||
[TestCase("/x/y", true, -1)] // yes!
|
||||
[TestCase("/y", true, 2001)]
|
||||
[TestCase("/y/z", true, 2002)]
|
||||
[TestCase("/b", true, 1001)] // (hence the 2004 collision)
|
||||
[TestCase("/b/c", true, 1002)] // (hence the 2005 collision)
|
||||
public void GetByRoute(string route, bool hide, int expected)
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("/test", 0);
|
||||
var cache = umbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
|
||||
|
||||
SettingsForTests.HideTopLevelNodeFromPath = hide;
|
||||
|
||||
const bool preview = true; // make sure we don't cache
|
||||
var content = cache.GetByRoute(umbracoContext, preview, route);
|
||||
if (expected < 0)
|
||||
{
|
||||
Assert.IsNull(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(expected, content.Id);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetByRouteCache()
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("/test", 0);
|
||||
var cache = umbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
|
||||
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false;
|
||||
|
||||
// make sure we cache
|
||||
PublishedContentCache.UnitTesting = false;
|
||||
const bool preview = false;
|
||||
|
||||
var content = cache.GetByRoute(umbracoContext, preview, "/a/b/c");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(1002, content.Id);
|
||||
|
||||
// GetByRoute registers a trusted route, which is cached both for
|
||||
// id -> route queries (fast GetUrl) and for route -> id queries
|
||||
// (fast inbound routing)
|
||||
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual(1, cachedRoutes.Count);
|
||||
Assert.IsTrue(cachedRoutes.ContainsKey(1002));
|
||||
Assert.AreEqual("/a/b/c", cachedRoutes[1002]);
|
||||
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(1, cachedIds.Count);
|
||||
Assert.IsTrue(cachedIds.ContainsKey("/a/b/c"));
|
||||
Assert.AreEqual(1002, cachedIds["/a/b/c"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace Umbraco.Tests.Routing
|
||||
protected override string GetXmlContent(int templateId)
|
||||
{
|
||||
return @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<!DOCTYPE root[
|
||||
<!DOCTYPE root[
|
||||
<!ELEMENT Doc ANY>
|
||||
<!ATTLIST Doc id ID #REQUIRED>
|
||||
]>
|
||||
@@ -302,11 +302,12 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
var cache = routingContext.UmbracoContext.ContentCache.InnerCache as PublishedContentCache;
|
||||
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
|
||||
|
||||
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
|
||||
Assert.AreEqual(7, cachedRoutes.Count);
|
||||
|
||||
var cachedIds = cache.RoutesCache.GetCachedIds();
|
||||
Assert.AreEqual(7, cachedIds.Count);
|
||||
Assert.AreEqual(0, cachedIds.Count);
|
||||
|
||||
CheckRoute(cachedRoutes, cachedIds, 1001, "1001/");
|
||||
CheckRoute(cachedRoutes, cachedIds, 10011, "10011/");
|
||||
@@ -328,12 +329,11 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual("http://domain1.com/fr/1001-2-1/", routingContext.UrlProvider.GetUrl(100121, new Uri("http://domain2.com"), false));
|
||||
}
|
||||
|
||||
void CheckRoute(IDictionary<int, string> routes, IDictionary<string, int> ids, int id, string route)
|
||||
private static void CheckRoute(IDictionary<int, string> routes, IDictionary<string, int> ids, int id, string route)
|
||||
{
|
||||
Assert.IsTrue(routes.ContainsKey(id));
|
||||
Assert.AreEqual(route, routes[id]);
|
||||
Assert.IsTrue(ids.ContainsKey(route));
|
||||
Assert.AreEqual(id, ids[route]);
|
||||
Assert.IsFalse(ids.ContainsKey(route));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Tests.Routing
|
||||
public void DoNotPolluteCache()
|
||||
{
|
||||
SettingsForTests.UseDirectoryUrls = true;
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains
|
||||
SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains
|
||||
|
||||
var settings = SettingsForTests.GenerateMockSettings();
|
||||
var request = Mock.Get(settings.RequestHandler);
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
RoutingContext routingContext;
|
||||
string url = "http://domain1.com/1001-1/1001-1-1";
|
||||
|
||||
|
||||
// get the nice url for 100111
|
||||
routingContext = GetRoutingContext(url, 9999, umbracoSettings: settings);
|
||||
Assert.AreEqual("http://domain2.com/1001-1-1/", routingContext.UrlProvider.GetUrl(100111, true));
|
||||
@@ -89,7 +89,7 @@ namespace Umbraco.Tests.Routing
|
||||
protected override string GetXmlContent(int templateId)
|
||||
{
|
||||
return @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<!DOCTYPE root[
|
||||
<!DOCTYPE root[
|
||||
<!ELEMENT Doc ANY>
|
||||
<!ATTLIST Doc id ID #REQUIRED>
|
||||
]>
|
||||
|
||||
@@ -35,18 +35,64 @@ namespace Umbraco.Tests.Services
|
||||
[SetUp]
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
//TODO Add test to verify there is only ONE newest document/content in cmsDocument table after updating.
|
||||
//TODO Add test to delete specific version (with and without deleting prior versions) and versions by date.
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that we don't unpublish all nodes when a node is deleted that has an invalid path of -1
|
||||
/// Note: it is actually the MoveToRecycleBin happening on the initial deletion of a node through the UI
|
||||
/// that causes the issue.
|
||||
/// Regression test: http://issues.umbraco.org/issue/U4-9336
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Moving_Node_To_Recycle_Bin_With_Invalid_Path()
|
||||
{
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var root = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 1);
|
||||
Assert.IsTrue(contentService.PublishWithStatus(root).Success);
|
||||
var content = contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0);
|
||||
Assert.IsTrue(contentService.PublishWithStatus(content).Success);
|
||||
var hierarchy = CreateContentHierarchy().OrderBy(x => x.Level).ToArray();
|
||||
contentService.Save(hierarchy, 0);
|
||||
foreach (var c in hierarchy)
|
||||
{
|
||||
Assert.IsTrue(contentService.PublishWithStatus(c).Success);
|
||||
}
|
||||
|
||||
//now make the data corrupted :/
|
||||
DatabaseContext.Database.Execute("UPDATE umbracoNode SET path = '-1' WHERE id = @id", new {id = content.Id});
|
||||
|
||||
//re-get with the corrupt path
|
||||
content = contentService.GetById(content.Id);
|
||||
|
||||
// here we get all descendants by the path of the node being moved to bin, and unpublish all of them.
|
||||
// since the path is invalid, there's logic in here to fix that if it's possible and re-persist the entity.
|
||||
var moveResult = ServiceContext.ContentService.WithResult().MoveToRecycleBin(content);
|
||||
|
||||
Assert.IsTrue(moveResult.Success);
|
||||
|
||||
//re-get with the fixed/moved path
|
||||
content = contentService.GetById(content.Id);
|
||||
|
||||
Assert.AreEqual("-1,-20," + content.Id, content.Path);
|
||||
|
||||
//re-get
|
||||
hierarchy = contentService.GetByIds(hierarchy.Select(x => x.Id).ToArray()).OrderBy(x => x.Level).ToArray();
|
||||
|
||||
Assert.That(hierarchy.All(c => c.Trashed == false), Is.True);
|
||||
Assert.That(hierarchy.All(c => c.Path.StartsWith("-1,-20") == false), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Remove_Scheduled_Publishing_Date()
|
||||
{
|
||||
@@ -104,7 +150,7 @@ namespace Umbraco.Tests.Services
|
||||
results.Add(contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0));
|
||||
}
|
||||
|
||||
var sortedGet = contentService.GetByIds(new[] {results[10].Id, results[5].Id, results[12].Id}).ToArray();
|
||||
var sortedGet = contentService.GetByIds(new[] { results[10].Id, results[5].Id, results[12].Id }).ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(sortedGet[0].Id, results[10].Id);
|
||||
@@ -121,7 +167,7 @@ namespace Umbraco.Tests.Services
|
||||
// Act
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0);
|
||||
contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0);
|
||||
}
|
||||
|
||||
// Assert
|
||||
@@ -230,7 +276,7 @@ namespace Umbraco.Tests.Services
|
||||
// Assert
|
||||
|
||||
//there should be no tags for this entity
|
||||
var tags = tagService.GetTagsForEntity(content1.Id);
|
||||
var tags = tagService.GetTagsForEntity(content1.Id);
|
||||
Assert.AreEqual(0, tags.Count());
|
||||
|
||||
//these tags should still be returned since they still have actively published content assigned
|
||||
@@ -265,7 +311,7 @@ namespace Umbraco.Tests.Services
|
||||
contentService.MoveToRecycleBin(content2);
|
||||
|
||||
// Assert
|
||||
|
||||
|
||||
//there should be no exposed content tags now that nothing is published.
|
||||
var allTags = tagService.GetAllContentTags();
|
||||
Assert.AreEqual(0, allTags.Count());
|
||||
@@ -395,7 +441,7 @@ namespace Umbraco.Tests.Services
|
||||
new PropertyType("test", DataTypeDatabaseType.Ntext, "tags")
|
||||
{
|
||||
DataTypeDefinitionId = 1041
|
||||
});
|
||||
});
|
||||
contentTypeService.Save(contentType);
|
||||
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => contentType.Id), 0, contentType.Alias) };
|
||||
|
||||
@@ -410,7 +456,7 @@ namespace Umbraco.Tests.Services
|
||||
var child2 = MockedContent.CreateSimpleContent(contentType, "child 2 content", content.Id);
|
||||
child2.SetTags("tags", new[] { "hello2", "world2" }, true);
|
||||
contentService.Save(child2);
|
||||
|
||||
|
||||
// Act
|
||||
contentService.PublishWithChildrenWithStatus(content, includeUnpublished: true);
|
||||
|
||||
@@ -461,34 +507,34 @@ namespace Umbraco.Tests.Services
|
||||
new { nodeId = content.Id, propTypeId = propertyTypeId }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Replace_Tag_Data_To_Published_Content()
|
||||
{
|
||||
[Test]
|
||||
public void Can_Replace_Tag_Data_To_Published_Content()
|
||||
{
|
||||
//Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true);
|
||||
contentType.PropertyGroups.First().PropertyTypes.Add(
|
||||
new PropertyType("test", DataTypeDatabaseType.Ntext, "tags")
|
||||
{
|
||||
DataTypeDefinitionId = 1041
|
||||
});
|
||||
{
|
||||
DataTypeDefinitionId = 1041
|
||||
});
|
||||
contentTypeService.Save(contentType);
|
||||
|
||||
var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1);
|
||||
|
||||
|
||||
|
||||
|
||||
// Act
|
||||
content.SetTags("tags", new[] { "hello", "world", "some", "tags" }, true);
|
||||
contentService.Publish(content);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(4, content.Properties["tags"].Value.ToString().Split(',').Distinct().Count());
|
||||
var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id;
|
||||
Assert.AreEqual(4, DatabaseContext.Database.ExecuteScalar<int>(
|
||||
"SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId",
|
||||
new {nodeId = content.Id, propTypeId = propertyTypeId}));
|
||||
}
|
||||
var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id;
|
||||
Assert.AreEqual(4, DatabaseContext.Database.ExecuteScalar<int>(
|
||||
"SELECT COUNT(*) FROM cmsTagRelationship WHERE nodeId=@nodeId AND propertyTypeId=@propTypeId",
|
||||
new { nodeId = content.Id, propTypeId = propertyTypeId }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Append_Tag_Data_To_Published_Content()
|
||||
@@ -506,7 +552,7 @@ namespace Umbraco.Tests.Services
|
||||
var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1);
|
||||
content.SetTags("tags", new[] { "hello", "world", "some", "tags" }, true);
|
||||
contentService.PublishWithStatus(content);
|
||||
|
||||
|
||||
// Act
|
||||
content.SetTags("tags", new[] { "another", "world" }, false);
|
||||
contentService.PublishWithStatus(content);
|
||||
@@ -548,9 +594,9 @@ namespace Umbraco.Tests.Services
|
||||
new { nodeId = content.Id, propTypeId = propertyTypeId }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Remove_Property_Type()
|
||||
{
|
||||
[Test]
|
||||
public void Can_Remove_Property_Type()
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
|
||||
@@ -560,9 +606,9 @@ namespace Umbraco.Tests.Services
|
||||
// Assert
|
||||
Assert.That(content, Is.Not.Null);
|
||||
Assert.That(content.HasIdentity, Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test]
|
||||
public void Can_Create_Content()
|
||||
{
|
||||
// Arrange
|
||||
@@ -575,7 +621,7 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(content, Is.Not.Null);
|
||||
Assert.That(content.HasIdentity, Is.False);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Content_Without_Explicitly_Set_User()
|
||||
{
|
||||
@@ -595,12 +641,12 @@ namespace Umbraco.Tests.Services
|
||||
public void Can_Save_New_Content_With_Explicit_User()
|
||||
{
|
||||
var user = new User(ServiceContext.UserService.GetUserTypeByAlias("admin"))
|
||||
{
|
||||
Name = "Test",
|
||||
Email = "test@test.com",
|
||||
Username = "test",
|
||||
{
|
||||
Name = "Test",
|
||||
Email = "test@test.com",
|
||||
Username = "test",
|
||||
RawPasswordValue = "test"
|
||||
};
|
||||
};
|
||||
ServiceContext.UserService.Save(user);
|
||||
var content = new Content("Test", -1, ServiceContext.ContentTypeService.GetContentType("umbTextpage"));
|
||||
|
||||
@@ -622,6 +668,17 @@ namespace Umbraco.Tests.Services
|
||||
Assert.Throws<Exception>(() => contentService.CreateContent("Test", -1, "umbAliasDoesntExist"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_Content_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = new Content(string.Empty, -1, ServiceContext.ContentTypeService.GetContentType("umbTextpage"));
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => contentService.Save(content));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Content_By_Id()
|
||||
{
|
||||
@@ -857,14 +914,14 @@ namespace Umbraco.Tests.Services
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
using (var uow = provider.GetUnitOfWork())
|
||||
{
|
||||
uow.Database.TruncateTable("cmsContentXml");
|
||||
uow.Database.TruncateTable("cmsContentXml");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for this test we are also going to save a revision for a content item that is not published, this is to ensure
|
||||
//that it's published version still makes it into the cmsContentXml table!
|
||||
contentService.Save(allContent.Last());
|
||||
|
||||
|
||||
// Act
|
||||
var published = contentService.RePublishAll(0);
|
||||
|
||||
@@ -872,7 +929,7 @@ namespace Umbraco.Tests.Services
|
||||
Assert.IsTrue(published);
|
||||
using (var uow = provider.GetUnitOfWork())
|
||||
{
|
||||
Assert.AreEqual(allContent.Count(), uow.Database.ExecuteScalar<int>("select count(*) from cmsContentXml"));
|
||||
Assert.AreEqual(allContent.Count(), uow.Database.ExecuteScalar<int>("select count(*) from cmsContentXml"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,7 +946,7 @@ namespace Umbraco.Tests.Services
|
||||
var allContent = rootContent.Concat(rootContent.SelectMany(x => x.Descendants())).ToList();
|
||||
//for testing we need to clear out the contentXml table so we can see if it worked
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
|
||||
|
||||
using (var uow = provider.GetUnitOfWork())
|
||||
{
|
||||
uow.Database.TruncateTable("cmsContentXml");
|
||||
@@ -899,7 +956,7 @@ namespace Umbraco.Tests.Services
|
||||
contentService.Save(allContent.Last());
|
||||
|
||||
// Act
|
||||
contentService.RePublishAll(new int[]{allContent.Last().ContentTypeId});
|
||||
contentService.RePublishAll(new int[] { allContent.Last().ContentTypeId });
|
||||
|
||||
// Assert
|
||||
using (var uow = provider.GetUnitOfWork())
|
||||
@@ -1085,7 +1142,7 @@ namespace Umbraco.Tests.Services
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = contentService.CreateContent("Home US", - 1, "umbTextpage", 0);
|
||||
var content = contentService.CreateContent("Home US", -1, "umbTextpage", 0);
|
||||
content.SetValue("author", "Barack Obama");
|
||||
|
||||
// Act
|
||||
@@ -1116,7 +1173,7 @@ namespace Umbraco.Tests.Services
|
||||
var savedVersion = content.Version;
|
||||
|
||||
// Act
|
||||
var publishedDescendants = ((ContentService) contentService).GetPublishedDescendants(root).ToList();
|
||||
var publishedDescendants = ((ContentService)contentService).GetPublishedDescendants(root).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.That(rootPublished, Is.True);
|
||||
@@ -1146,7 +1203,7 @@ namespace Umbraco.Tests.Services
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = contentService.CreateContent("Home US", - 1, "umbTextpage", 0);
|
||||
var content = contentService.CreateContent("Home US", -1, "umbTextpage", 0);
|
||||
content.SetValue("author", "Barack Obama");
|
||||
|
||||
// Act
|
||||
@@ -1166,7 +1223,7 @@ namespace Umbraco.Tests.Services
|
||||
var contentType = contentTypeService.GetContentType("umbTextpage");
|
||||
Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Subpage 1", NodeDto.NodeIdSeed + 2);
|
||||
Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Subpage 2", NodeDto.NodeIdSeed + 2);
|
||||
var list = new List<IContent> {subpage, subpage2};
|
||||
var list = new List<IContent> { subpage, subpage2 };
|
||||
|
||||
// Act
|
||||
contentService.Save(list, 0);
|
||||
@@ -1186,9 +1243,9 @@ namespace Umbraco.Tests.Services
|
||||
contentService.Save(hierarchy, 0);
|
||||
|
||||
Assert.That(hierarchy.Any(), Is.True);
|
||||
Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False);
|
||||
//all parent id's should be ok, they are lazy and if they equal zero an exception will be thrown
|
||||
Assert.DoesNotThrow(() => hierarchy.Any(x => x.ParentId != 0));
|
||||
Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False);
|
||||
//all parent id's should be ok, they are lazy and if they equal zero an exception will be thrown
|
||||
Assert.DoesNotThrow(() => hierarchy.Any(x => x.ParentId != 0));
|
||||
|
||||
}
|
||||
|
||||
@@ -1375,7 +1432,7 @@ namespace Umbraco.Tests.Services
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
var temp = MockedContent.CreateSimpleContent(contentType, "Simple Text Page", -1);
|
||||
var prop = temp.Properties.First();
|
||||
temp.SetTags(prop.Alias, new[] {"hello", "world"}, true);
|
||||
temp.SetTags(prop.Alias, new[] { "hello", "world" }, true);
|
||||
var status = contentService.PublishWithStatus(temp);
|
||||
|
||||
// Act
|
||||
@@ -1418,14 +1475,14 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
[Test]
|
||||
public void Can_Save_Lazy_Content()
|
||||
{
|
||||
var unitOfWork = PetaPocoUnitOfWorkProvider.CreateUnitOfWork(Mock.Of<ILogger>());
|
||||
{
|
||||
var unitOfWork = PetaPocoUnitOfWorkProvider.CreateUnitOfWork(Mock.Of<ILogger>());
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
var root = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 1);
|
||||
|
||||
var c = new Lazy<IContent>(() => MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Page", root.Id));
|
||||
var c2 = new Lazy<IContent>(() => MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage", c.Value.Id));
|
||||
var list = new List<Lazy<IContent>> {c, c2};
|
||||
var list = new List<Lazy<IContent>> { c, c2 };
|
||||
|
||||
ContentTypeRepository contentTypeRepository;
|
||||
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
|
||||
@@ -1443,9 +1500,9 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(c2.Value.Id > 0, Is.True);
|
||||
|
||||
Assert.That(c.Value.ParentId > 0, Is.True);
|
||||
Assert.That(c2.Value.ParentId > 0, Is.True);
|
||||
Assert.That(c2.Value.ParentId > 0, Is.True);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -1468,20 +1525,20 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(hasPublishedVersion, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Verify_Property_Types_On_Content()
|
||||
{
|
||||
[Test]
|
||||
public void Can_Verify_Property_Types_On_Content()
|
||||
{
|
||||
// Arrange
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var contentType = MockedContentTypes.CreateAllTypesContentType("allDataTypes", "All DataTypes");
|
||||
contentTypeService.Save(contentType);
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = MockedContent.CreateAllTypesContent(contentType, "Random Content", -1);
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = MockedContent.CreateAllTypesContent(contentType, "Random Content", -1);
|
||||
contentService.Save(content);
|
||||
var id = content.Id;
|
||||
var id = content.Id;
|
||||
|
||||
// Act
|
||||
var sut = contentService.GetById(id);
|
||||
var sut = contentService.GetById(id);
|
||||
|
||||
// Arrange
|
||||
Assert.That(sut.GetValue<bool>("isTrue"), Is.True);
|
||||
@@ -1496,7 +1553,7 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(sut.GetValue<DateTime>("dateTime").ToString("G"), Is.EqualTo(content.GetValue<DateTime>("dateTime").ToString("G")));
|
||||
Assert.That(sut.GetValue<string>("colorPicker"), Is.EqualTo("black"));
|
||||
//that one is gone in 7.4
|
||||
//Assert.That(sut.GetValue<string>("folderBrowser"), Is.Null);
|
||||
//Assert.That(sut.GetValue<string>("folderBrowser"), Is.Null);
|
||||
Assert.That(sut.GetValue<string>("ddlMultiple"), Is.EqualTo("1234,1235"));
|
||||
Assert.That(sut.GetValue<string>("rbList"), Is.EqualTo("random"));
|
||||
Assert.That(sut.GetValue<DateTime>("date").ToString("G"), Is.EqualTo(content.GetValue<DateTime>("date").ToString("G")));
|
||||
@@ -1507,23 +1564,23 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(sut.GetValue<int>("memberPicker"), Is.EqualTo(1092));
|
||||
Assert.That(sut.GetValue<string>("relatedLinks"), Is.EqualTo("<links><link title=\"google\" link=\"http://google.com\" type=\"external\" newwindow=\"0\" /></links>"));
|
||||
Assert.That(sut.GetValue<string>("tags"), Is.EqualTo("this,is,tags"));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Previous_Versions_Not_Latest()
|
||||
{
|
||||
[Test]
|
||||
public void Can_Delete_Previous_Versions_Not_Latest()
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = contentService.GetById(NodeDto.NodeIdSeed + 4);
|
||||
var version = content.Version;
|
||||
var version = content.Version;
|
||||
|
||||
// Act
|
||||
// Act
|
||||
contentService.DeleteVersion(NodeDto.NodeIdSeed + 4, version, true, 0);
|
||||
var sut = contentService.GetById(NodeDto.NodeIdSeed + 4);
|
||||
|
||||
// Assert
|
||||
Assert.That(sut.Version, Is.EqualTo(version));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Content_Xml_Created()
|
||||
@@ -1542,7 +1599,7 @@ namespace Umbraco.Tests.Services
|
||||
}
|
||||
|
||||
contentService.Publish(content);
|
||||
|
||||
|
||||
using (var uow = provider.GetUnitOfWork())
|
||||
{
|
||||
Assert.IsTrue(uow.Database.Exists<ContentXmlDto>(content.Id));
|
||||
@@ -1559,10 +1616,10 @@ namespace Umbraco.Tests.Services
|
||||
contentService.Save(content);
|
||||
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
|
||||
|
||||
using (var uow = provider.GetUnitOfWork())
|
||||
{
|
||||
Assert.IsTrue(uow.Database.SingleOrDefault<PreviewXmlDto>("WHERE nodeId=@nodeId AND versionId = @versionId", new{nodeId = content.Id, versionId = content.Version}) != null);
|
||||
Assert.IsTrue(uow.Database.SingleOrDefault<PreviewXmlDto>("WHERE nodeId=@nodeId AND versionId = @versionId", new { nodeId = content.Id, versionId = content.Version }) != null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1665,11 +1722,11 @@ namespace Umbraco.Tests.Services
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
var root = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 1);
|
||||
|
||||
var list = new List<IContent>();
|
||||
var list = new List<IContent>();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var content = MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Page " + i, root);
|
||||
var content = MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Page " + i, root);
|
||||
|
||||
list.Add(content);
|
||||
list.AddRange(CreateChildrenOf(contentType, content, 4));
|
||||
@@ -1680,12 +1737,12 @@ namespace Umbraco.Tests.Services
|
||||
return list;
|
||||
}
|
||||
|
||||
private IEnumerable<IContent> CreateChildrenOf(IContentType contentType, IContent content, int depth)
|
||||
private IEnumerable<IContent> CreateChildrenOf(IContentType contentType, IContent content, int depth)
|
||||
{
|
||||
var list = new List<IContent>();
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
var c = MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage " + i, content);
|
||||
var c = MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage " + i, content);
|
||||
list.Add(c);
|
||||
|
||||
Debug.Print("Created: 'Hierarchy Simple Text Subpage {0}' - Depth: {1}", i, depth);
|
||||
|
||||
@@ -304,6 +304,42 @@ namespace Umbraco.Tests.Services
|
||||
Assert.IsNull(deletedContentType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Container()
|
||||
{
|
||||
// Arrange
|
||||
var cts = ServiceContext.ContentTypeService;
|
||||
|
||||
// Act
|
||||
var container = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid);
|
||||
container.Name = "container1";
|
||||
cts.SaveContentTypeContainer(container);
|
||||
|
||||
// Assert
|
||||
var createdContainer = cts.GetContentTypeContainer(container.Id);
|
||||
Assert.IsNotNull(createdContainer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_All_Containers()
|
||||
{
|
||||
// Arrange
|
||||
var cts = ServiceContext.ContentTypeService;
|
||||
|
||||
// Act
|
||||
var container1 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid);
|
||||
container1.Name = "container1";
|
||||
cts.SaveContentTypeContainer(container1);
|
||||
|
||||
var container2 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid);
|
||||
container2.Name = "container2";
|
||||
cts.SaveContentTypeContainer(container2);
|
||||
|
||||
// Assert
|
||||
var containers = cts.GetContentTypeContainers(new int[0]);
|
||||
Assert.AreEqual(2, containers.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Deleting_ContentType_Sends_Correct_Number_Of_DeletedEntities_In_Events()
|
||||
{
|
||||
@@ -717,6 +753,16 @@ namespace Umbraco.Tests.Services
|
||||
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_ContentType_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("contentType", string.Empty);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => ServiceContext.ContentTypeService.Save(contentType));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Rename_PropertyType_Alias_On_Composition_Which_Would_Cause_Conflict_In_Other_Composition()
|
||||
{
|
||||
|
||||
@@ -221,5 +221,18 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreEqual("preVal1", preVals.PreValuesAsArray.First().Value);
|
||||
Assert.AreEqual("preVal2", preVals.PreValuesAsArray.Last().Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_DataType_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
var dataTypeService = ServiceContext.DataTypeService;
|
||||
|
||||
// Act
|
||||
var dataTypeDefinition = new DataTypeDefinition(-1, "Test.TestEditor") { Name = string.Empty, DatabaseType = DataTypeDatabaseType.Ntext };
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => dataTypeService.Save(dataTypeDefinition));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -217,6 +218,17 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_Macro_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
var macroService = ServiceContext.MacroService;
|
||||
var macro = new Macro("test", string.Empty, scriptPath: "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => macroService.Save(macro));
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void Can_Get_Many_By_Alias()
|
||||
//{
|
||||
|
||||
@@ -81,6 +81,19 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(mediaChild.Trashed, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_Media_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
var mediaService = ServiceContext.MediaService;
|
||||
var mediaType = MockedContentTypes.CreateVideoMediaType();
|
||||
ServiceContext.ContentTypeService.Save(mediaType);
|
||||
var media = mediaService.CreateMedia(string.Empty, -1, "video");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => mediaService.Save(media));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Content_Xml_Created()
|
||||
{
|
||||
|
||||
@@ -185,6 +185,18 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreEqual(2, membersInRole.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_Member_With_Empty_Name()
|
||||
{
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
IMember member = MockedMember.CreateSimpleMember(memberType, string.Empty, "test@test.com", "pass", "test");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => ServiceContext.MemberService.Save(member));
|
||||
|
||||
}
|
||||
|
||||
[TestCase("MyTestRole1", "test1", StringPropertyMatchType.StartsWith, 1)]
|
||||
[TestCase("MyTestRole1", "test", StringPropertyMatchType.StartsWith, 3)]
|
||||
[TestCase("MyTestRole1", "test1", StringPropertyMatchType.Exact, 1)]
|
||||
|
||||
@@ -173,6 +173,16 @@ namespace Umbraco.Tests.Services
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_MemberType_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType("memberTypeAlias", string.Empty);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => ServiceContext.MemberTypeService.Save(memberType));
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void Can_Save_MemberType_Structure_And_Create_A_Member_Based_On_It()
|
||||
//{
|
||||
|
||||
@@ -490,6 +490,43 @@ namespace Umbraco.Tests.Services
|
||||
Assert.IsTrue(result4.AllowedSections.Contains("test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Create_User_With_Empty_Username()
|
||||
{
|
||||
// Arrange
|
||||
var userService = ServiceContext.UserService;
|
||||
var userType = userService.GetUserTypeByAlias("admin");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => userService.CreateUserWithIdentity(string.Empty, "john@umbraco.io", userType));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_User_With_Empty_Username()
|
||||
{
|
||||
// Arrange
|
||||
var userService = ServiceContext.UserService;
|
||||
var userType = userService.GetUserTypeByAlias("admin");
|
||||
var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io", userType);
|
||||
user.Username = string.Empty;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => userService.Save(user));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Cannot_Save_User_With_Empty_Name()
|
||||
{
|
||||
// Arrange
|
||||
var userService = ServiceContext.UserService;
|
||||
var userType = userService.GetUserTypeByAlias("admin");
|
||||
var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io", userType);
|
||||
user.Name = string.Empty;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => userService.Save(user));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_By_Profile_Username()
|
||||
{
|
||||
|
||||
@@ -53,41 +53,33 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.80.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.80\lib\net45\Examine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\log4net-mediumtrust.2.0.0\lib\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq">
|
||||
<Reference Include="Moq, Version=4.1.1309.919, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
@@ -95,14 +87,12 @@
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=2.6.2.12296, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Semver">
|
||||
<Reference Include="Semver, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\semver.1.1.2\lib\net45\Semver.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
@@ -111,17 +101,14 @@
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.Entity.Design" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
@@ -131,46 +118,39 @@
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.SelfHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.SelfHost.4.0.30506.0\lib\net40\System.Web.Http.SelfHost.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.WebHost, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WebDriver">
|
||||
<Reference Include="WebDriver, Version=2.32.0.0, Culture=neutral, PublicKeyToken=1c2bd1631853048f, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Selenium.WebDriver.2.32.0\lib\net40\WebDriver.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
@@ -181,8 +161,11 @@
|
||||
<Compile Include="Persistence\PetaPocoCachesTest.cs" />
|
||||
<Compile Include="Persistence\PetaPocoExpressionsTests.cs" />
|
||||
<Compile Include="Persistence\Repositories\RedirectUrlRepositoryTests.cs" />
|
||||
<Compile Include="Routing\NiceUrlRoutesTests.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
|
||||
<Compile Include="TryConvertToTests.cs" />
|
||||
<Compile Include="UmbracoExamine\RandomIdRAMDirectory.cs" />
|
||||
<Compile Include="UmbracoExamine\UmbracoContentIndexerTests.cs" />
|
||||
<Compile Include="Web\AngularIntegration\AngularAntiForgeryTests.cs" />
|
||||
<Compile Include="Web\AngularIntegration\ContentModelSerializationTests.cs" />
|
||||
<Compile Include="Web\AngularIntegration\JsInitializationTests.cs" />
|
||||
@@ -612,9 +595,9 @@
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<EmbeddedResource Include="TreesAndSections\applications.config" />
|
||||
<EmbeddedResource Include="TreesAndSections\trees.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Packaging\Packages\Document_Type_Picker_1.1.umb" />
|
||||
<None Include="UmbracoExamine\TestFiles\umbraco-sort.config">
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Examine;
|
||||
using Lucene.Net.Analysis.Standard;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.Store;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
@@ -15,53 +17,39 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
[Test]
|
||||
public void Events_Ignoring_Node()
|
||||
{
|
||||
//change the parent id so that they are all ignored
|
||||
var existingCriteria = _indexer.IndexerData;
|
||||
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
999); //change to 999
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
//change the parent id so that they are all ignored
|
||||
var existingCriteria = indexer.IndexerData;
|
||||
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
999); //change to 999
|
||||
|
||||
var isIgnored = false;
|
||||
var isIgnored = false;
|
||||
|
||||
EventHandler<IndexingNodeDataEventArgs> ignoringNode = (s, e) =>
|
||||
{
|
||||
isIgnored = true;
|
||||
};
|
||||
EventHandler<IndexingNodeDataEventArgs> ignoringNode = (s, e) =>
|
||||
{
|
||||
isIgnored = true;
|
||||
};
|
||||
|
||||
_indexer.IgnoringNode += ignoringNode;
|
||||
indexer.IgnoringNode += ignoringNode;
|
||||
|
||||
//get a node from the data repo
|
||||
var node = _contentService.GetPublishedContentByXPath("//*[string-length(@id)>0 and number(@id)>0]")
|
||||
.Root
|
||||
.Elements()
|
||||
.First();
|
||||
//get a node from the data repo
|
||||
var node = _contentService.GetPublishedContentByXPath("//*[string-length(@id)>0 and number(@id)>0]")
|
||||
.Root
|
||||
.Elements()
|
||||
.First();
|
||||
|
||||
_indexer.ReIndexNode(node, IndexTypes.Content);
|
||||
indexer.ReIndexNode(node, IndexTypes.Content);
|
||||
|
||||
|
||||
Assert.IsTrue(isIgnored);
|
||||
|
||||
Assert.IsTrue(isIgnored);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly TestContentService _contentService = new TestContentService();
|
||||
private static UmbracoExamineSearcher _searcher;
|
||||
private static UmbracoContentIndexer _indexer;
|
||||
private Lucene.Net.Store.Directory _luceneDir;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_luceneDir = new RAMDirectory();
|
||||
_indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir);
|
||||
_indexer.RebuildIndex();
|
||||
_searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir);
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
_luceneDir.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Examine.LuceneEngine.Config;
|
||||
using Examine.LuceneEngine.Providers;
|
||||
using Lucene.Net.Analysis;
|
||||
using Lucene.Net.Analysis.Standard;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.Store;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
@@ -33,7 +34,7 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
internal static class IndexInitializer
|
||||
{
|
||||
public static UmbracoContentIndexer GetUmbracoIndexer(
|
||||
Directory luceneDir,
|
||||
IndexWriter writer,
|
||||
Analyzer analyzer = null,
|
||||
IDataService dataService = null,
|
||||
IContentService contentService = null,
|
||||
@@ -41,7 +42,8 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
IDataTypeService dataTypeService = null,
|
||||
IMemberService memberService = null,
|
||||
IUserService userService = null,
|
||||
IContentTypeService contentTypeService = null)
|
||||
IContentTypeService contentTypeService = null,
|
||||
bool supportUnpublishedContent = false)
|
||||
{
|
||||
if (dataService == null)
|
||||
{
|
||||
@@ -177,15 +179,17 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
var indexCriteria = indexSet.ToIndexCriteria(dataService, UmbracoContentIndexer.IndexFieldPolicies);
|
||||
|
||||
var i = new UmbracoContentIndexer(indexCriteria,
|
||||
luceneDir, //custom lucene directory
|
||||
dataService,
|
||||
contentService,
|
||||
mediaService,
|
||||
dataTypeService,
|
||||
userService,
|
||||
contentTypeService,
|
||||
analyzer,
|
||||
false);
|
||||
writer,
|
||||
dataService,
|
||||
contentService,
|
||||
mediaService,
|
||||
dataTypeService,
|
||||
userService,
|
||||
contentTypeService,
|
||||
false)
|
||||
{
|
||||
SupportUnpublishedContent = supportUnpublishedContent
|
||||
};
|
||||
|
||||
//i.IndexSecondsInterval = 1;
|
||||
|
||||
@@ -193,13 +197,14 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
|
||||
return i;
|
||||
}
|
||||
public static UmbracoExamineSearcher GetUmbracoSearcher(Directory luceneDir, Analyzer analyzer = null)
|
||||
|
||||
public static UmbracoExamineSearcher GetUmbracoSearcher(IndexWriter writer, Analyzer analyzer = null)
|
||||
{
|
||||
if (analyzer == null)
|
||||
{
|
||||
analyzer = new StandardAnalyzer(Version.LUCENE_29);
|
||||
}
|
||||
return new UmbracoExamineSearcher(luceneDir, analyzer);
|
||||
return new UmbracoExamineSearcher(writer, analyzer);
|
||||
}
|
||||
|
||||
public static LuceneSearcher GetLuceneSearcher(Directory luceneDir)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Examine;
|
||||
using Examine.LuceneEngine;
|
||||
using Examine.LuceneEngine.Providers;
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Examine.SearchCriteria;
|
||||
using Lucene.Net.Analysis.Standard;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.Search;
|
||||
using Lucene.Net.Store;
|
||||
@@ -15,218 +15,230 @@ using UmbracoExamine;
|
||||
|
||||
namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Tests the standard indexing capabilities
|
||||
/// </summary>
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
[TestFixture, RequiresSTA]
|
||||
public class IndexTest : ExamineBaseTest
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Check that the node signalled as protected in the content service is not present in the index.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Index_Protected_Content_Not_Indexed()
|
||||
{
|
||||
|
||||
///// <summary>
|
||||
/// <summary>
|
||||
/// Check that the node signalled as protected in the content service is not present in the index.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Index_Protected_Content_Not_Indexed()
|
||||
{
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
|
||||
var protectedQuery = new BooleanQuery();
|
||||
protectedQuery.Add(
|
||||
new BooleanClause(
|
||||
new TermQuery(new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content)),
|
||||
BooleanClause.Occur.MUST));
|
||||
var protectedQuery = new BooleanQuery();
|
||||
protectedQuery.Add(
|
||||
new BooleanClause(
|
||||
new TermQuery(new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content)),
|
||||
BooleanClause.Occur.MUST));
|
||||
|
||||
protectedQuery.Add(
|
||||
new BooleanClause(
|
||||
new TermQuery(new Term(LuceneIndexer.IndexNodeIdFieldName, TestContentService.ProtectedNode.ToString())),
|
||||
BooleanClause.Occur.MUST));
|
||||
protectedQuery.Add(
|
||||
new BooleanClause(
|
||||
new TermQuery(new Term(LuceneIndexer.IndexNodeIdFieldName, TestContentService.ProtectedNode.ToString())),
|
||||
BooleanClause.Occur.MUST));
|
||||
|
||||
var collector = new AllHitsCollector(false, true);
|
||||
var s = _searcher.GetSearcher();
|
||||
s.Search(protectedQuery, collector);
|
||||
var collector = new AllHitsCollector(false, true);
|
||||
var s = searcher.GetSearcher();
|
||||
s.Search(protectedQuery, collector);
|
||||
|
||||
Assert.AreEqual(0, collector.Count, "Protected node should not be indexed");
|
||||
Assert.AreEqual(0, collector.Count, "Protected node should not be indexed");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID()
|
||||
{
|
||||
//change parent id to 1116
|
||||
var existingCriteria = _indexer.IndexerData;
|
||||
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
1116);
|
||||
|
||||
//rebuild so it excludes children unless they are under 1116
|
||||
_indexer.RebuildIndex();
|
||||
[Test]
|
||||
public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID()
|
||||
{
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
|
||||
//ensure that node 2112 doesn't exist
|
||||
var results = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile());
|
||||
Assert.AreEqual(0, results.Count());
|
||||
var mediaService = new TestMediaService();
|
||||
|
||||
//get a node from the data repo (this one exists underneath 2222)
|
||||
var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
|
||||
.Root
|
||||
.Elements()
|
||||
.Where(x => (int)x.Attribute("id") == 2112)
|
||||
.First();
|
||||
//change parent id to 1116
|
||||
var existingCriteria = indexer.IndexerData;
|
||||
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
1116);
|
||||
|
||||
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
|
||||
Assert.AreEqual("-1,1111,2222,2112", currPath);
|
||||
//rebuild so it excludes children unless they are under 1116
|
||||
indexer.RebuildIndex();
|
||||
|
||||
//now mimic moving 2112 to 1116
|
||||
//node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
|
||||
node.SetAttributeValue("path", "-1,1116,2112");
|
||||
node.SetAttributeValue("parentID", "1116");
|
||||
//ensure that node 2112 doesn't exist
|
||||
var results = searcher.Search(searcher.CreateSearchCriteria().Id(2112).Compile());
|
||||
Assert.AreEqual(0, results.TotalItemCount);
|
||||
|
||||
//now reindex the node, this should first delete it and then WILL add it because of the parent id constraint
|
||||
_indexer.ReIndexNode(node, IndexTypes.Media);
|
||||
//get a node from the data repo (this one exists underneath 2222)
|
||||
var node = mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
|
||||
.Root
|
||||
.Elements()
|
||||
.First(x => (int)x.Attribute("id") == 2112);
|
||||
|
||||
//RESET the parent id
|
||||
existingCriteria = ((IndexCriteria)_indexer.IndexerData);
|
||||
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
null);
|
||||
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
|
||||
Assert.AreEqual("-1,1111,2222,2112", currPath);
|
||||
|
||||
//now ensure it's deleted
|
||||
var newResults = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile());
|
||||
Assert.AreEqual(1, newResults.Count());
|
||||
}
|
||||
//now mimic moving 2112 to 1116
|
||||
//node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
|
||||
node.SetAttributeValue("path", "-1,1116,2112");
|
||||
node.SetAttributeValue("parentID", "1116");
|
||||
|
||||
[Test]
|
||||
[Ignore]
|
||||
public void Index_Move_Media_To_Non_Indexable_ParentID()
|
||||
{
|
||||
//get a node from the data repo (this one exists underneath 2222)
|
||||
var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
|
||||
.Root
|
||||
.Elements()
|
||||
.Where(x => (int)x.Attribute("id") == 2112)
|
||||
.First();
|
||||
//now reindex the node, this should first delete it and then WILL add it because of the parent id constraint
|
||||
indexer.ReIndexNode(node, IndexTypes.Media);
|
||||
|
||||
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
|
||||
Assert.AreEqual("-1,1111,2222,2112", currPath);
|
||||
//RESET the parent id
|
||||
existingCriteria = ((IndexCriteria)indexer.IndexerData);
|
||||
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
null);
|
||||
|
||||
//ensure it's indexed
|
||||
_indexer.ReIndexNode(node, IndexTypes.Media);
|
||||
//now ensure it's deleted
|
||||
var newResults = searcher.Search(searcher.CreateSearchCriteria().Id(2112).Compile());
|
||||
Assert.AreEqual(1, newResults.TotalItemCount);
|
||||
}
|
||||
|
||||
//change the parent node id to be the one it used to exist under
|
||||
var existingCriteria = _indexer.IndexerData;
|
||||
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
2222);
|
||||
|
||||
}
|
||||
|
||||
//now mimic moving the node underneath 1116 instead of 2222
|
||||
node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
|
||||
node.SetAttributeValue("parentID", "1116");
|
||||
[Test]
|
||||
public void Index_Move_Media_To_Non_Indexable_ParentID()
|
||||
{
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
|
||||
//now reindex the node, this should first delete it and then NOT add it because of the parent id constraint
|
||||
_indexer.ReIndexNode(node, IndexTypes.Media);
|
||||
var mediaService = new TestMediaService();
|
||||
|
||||
//RESET the parent id
|
||||
existingCriteria = ((IndexCriteria)_indexer.IndexerData);
|
||||
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
null);
|
||||
//get a node from the data repo (this one exists underneath 2222)
|
||||
var node = mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
|
||||
.Root
|
||||
.Elements()
|
||||
.First(x => (int)x.Attribute("id") == 2112);
|
||||
|
||||
//now ensure it's deleted
|
||||
var results = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile());
|
||||
Assert.AreEqual(0, results.Count());
|
||||
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
|
||||
Assert.AreEqual("-1,1111,2222,2112", currPath);
|
||||
|
||||
}
|
||||
//ensure it's indexed
|
||||
indexer.ReIndexNode(node, IndexTypes.Media);
|
||||
|
||||
//change the parent node id to be the one it used to exist under
|
||||
var existingCriteria = indexer.IndexerData;
|
||||
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
2222);
|
||||
|
||||
//now mimic moving the node underneath 1116 instead of 2222
|
||||
node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
|
||||
node.SetAttributeValue("parentID", "1116");
|
||||
|
||||
//now reindex the node, this should first delete it and then NOT add it because of the parent id constraint
|
||||
indexer.ReIndexNode(node, IndexTypes.Media);
|
||||
|
||||
//RESET the parent id
|
||||
existingCriteria = ((IndexCriteria)indexer.IndexerData);
|
||||
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
|
||||
null);
|
||||
|
||||
//now ensure it's deleted
|
||||
var results = searcher.Search(searcher.CreateSearchCriteria().Id(2112).Compile());
|
||||
Assert.AreEqual(0, results.TotalItemCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will ensure that all 'Content' (not media) is cleared from the index using the Lucene API directly.
|
||||
/// We then call the Examine method to re-index Content and do some comparisons to ensure that it worked correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Index_Reindex_Content()
|
||||
{
|
||||
var s = (IndexSearcher)_searcher.GetSearcher();
|
||||
/// <summary>
|
||||
/// This will ensure that all 'Content' (not media) is cleared from the index using the Lucene API directly.
|
||||
/// We then call the Examine method to re-index Content and do some comparisons to ensure that it worked correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Index_Reindex_Content()
|
||||
{
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer, supportUnpublishedContent: true))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
|
||||
//first delete all 'Content' (not media). This is done by directly manipulating the index with the Lucene API, not examine!
|
||||
|
||||
var contentTerm = new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content);
|
||||
var writer = _indexer.GetIndexWriter();
|
||||
writer.DeleteDocuments(contentTerm);
|
||||
writer.Commit();
|
||||
|
||||
var s = (IndexSearcher)searcher.GetSearcher();
|
||||
|
||||
//make sure the content is gone. This is done with lucene APIs, not examine!
|
||||
var collector = new AllHitsCollector(false, true);
|
||||
var query = new TermQuery(contentTerm);
|
||||
s = (IndexSearcher)_searcher.GetSearcher(); //make sure the searcher is up do date.
|
||||
s.Search(query, collector);
|
||||
Assert.AreEqual(0, collector.Count);
|
||||
//first delete all 'Content' (not media). This is done by directly manipulating the index with the Lucene API, not examine!
|
||||
|
||||
//call our indexing methods
|
||||
_indexer.IndexAll(IndexTypes.Content);
|
||||
var contentTerm = new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content);
|
||||
writer.DeleteDocuments(contentTerm);
|
||||
writer.Commit();
|
||||
|
||||
collector = new AllHitsCollector(false, true);
|
||||
s = (IndexSearcher)_searcher.GetSearcher(); //make sure the searcher is up do date.
|
||||
s.Search(query, collector);
|
||||
//var ids = new List<string>();
|
||||
//for (var i = 0; i < collector.Count;i++)
|
||||
//{
|
||||
// ids.Add(s.Doc(collector.GetDocId(i)).GetValues("__NodeId")[0]);
|
||||
//}
|
||||
Assert.AreEqual(20, collector.Count);
|
||||
}
|
||||
//make sure the content is gone. This is done with lucene APIs, not examine!
|
||||
var collector = new AllHitsCollector(false, true);
|
||||
var query = new TermQuery(contentTerm);
|
||||
s = (IndexSearcher)searcher.GetSearcher(); //make sure the searcher is up do date.
|
||||
s.Search(query, collector);
|
||||
Assert.AreEqual(0, collector.Count);
|
||||
|
||||
/// <summary>
|
||||
/// This will delete an item from the index and ensure that all children of the node are deleted too!
|
||||
/// </summary>
|
||||
[Test]
|
||||
[Ignore]
|
||||
public void Index_Delete_Index_Item_Ensure_Heirarchy_Removed()
|
||||
{
|
||||
//call our indexing methods
|
||||
indexer.IndexAll(IndexTypes.Content);
|
||||
|
||||
//now delete a node that has children
|
||||
collector = new AllHitsCollector(false, true);
|
||||
s = (IndexSearcher)searcher.GetSearcher(); //make sure the searcher is up do date.
|
||||
s.Search(query, collector);
|
||||
//var ids = new List<string>();
|
||||
//for (var i = 0; i < collector.Count;i++)
|
||||
//{
|
||||
// ids.Add(s.Doc(collector.GetDocId(i)).GetValues("__NodeId")[0]);
|
||||
//}
|
||||
Assert.AreEqual(21, collector.Count);
|
||||
}
|
||||
}
|
||||
|
||||
_indexer.DeleteFromIndex(1140.ToString());
|
||||
//this node had children: 1141 & 1142, let's ensure they are also removed
|
||||
/// <summary>
|
||||
/// This will delete an item from the index and ensure that all children of the node are deleted too!
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Index_Delete_Index_Item_Ensure_Heirarchy_Removed()
|
||||
{
|
||||
|
||||
var results = _searcher.Search(_searcher.CreateSearchCriteria().Id(1141).Compile());
|
||||
Assert.AreEqual(0, results.Count());
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
|
||||
results = _searcher.Search(_searcher.CreateSearchCriteria().Id(1142).Compile());
|
||||
Assert.AreEqual(0, results.Count());
|
||||
//now delete a node that has children
|
||||
|
||||
}
|
||||
indexer.DeleteFromIndex(1140.ToString());
|
||||
//this node had children: 1141 & 1142, let's ensure they are also removed
|
||||
|
||||
#region Private methods and properties
|
||||
var results = searcher.Search(searcher.CreateSearchCriteria().Id(1141).Compile());
|
||||
Assert.AreEqual(0, results.TotalItemCount);
|
||||
|
||||
private readonly TestContentService _contentService = new TestContentService();
|
||||
private readonly TestMediaService _mediaService = new TestMediaService();
|
||||
|
||||
private static UmbracoExamineSearcher _searcher;
|
||||
private static UmbracoContentIndexer _indexer;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialize and Cleanup
|
||||
|
||||
private Lucene.Net.Store.Directory _luceneDir;
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
_luceneDir.Dispose();
|
||||
results = searcher.Search(searcher.CreateSearchCriteria().Id(1142).Compile());
|
||||
Assert.AreEqual(0, results.TotalItemCount);
|
||||
}
|
||||
}
|
||||
|
||||
#region Initialize and Cleanup
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
UmbracoExamineSearcher.DisableInitializationCheck = null;
|
||||
BaseUmbracoIndexer.DisableInitializationCheck = null;
|
||||
}
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_luceneDir = new RAMDirectory();
|
||||
_indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir);
|
||||
_indexer.RebuildIndex();
|
||||
_searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using Lucene.Net.Store;
|
||||
|
||||
namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
public class RandomIdRAMDirectory : RAMDirectory
|
||||
{
|
||||
private readonly string _lockId = Guid.NewGuid().ToString();
|
||||
public override string GetLockID()
|
||||
{
|
||||
return _lockId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ using Examine.LuceneEngine.Providers;
|
||||
using Lucene.Net.Store;
|
||||
using NUnit.Framework;
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Lucene.Net.Analysis.Standard;
|
||||
using Lucene.Net.Index;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.UmbracoExamine
|
||||
@@ -20,19 +22,17 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
[Test]
|
||||
public void Test_Sort_Order_Sorting()
|
||||
{
|
||||
//var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\SearchTests", Guid.NewGuid().ToString()));
|
||||
//System.IO.Directory.CreateDirectory(newIndexFolder.FullName);
|
||||
|
||||
using (var luceneDir = new RAMDirectory())
|
||||
//using (var luceneDir = new SimpleFSDirectory(newIndexFolder))
|
||||
{
|
||||
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir, null,
|
||||
using (var luceneDir = new RandomIdRAMDirectory())
|
||||
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
|
||||
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer, null,
|
||||
new TestDataService()
|
||||
{
|
||||
ContentService = new TestContentService(TestFiles.umbraco_sort)
|
||||
});
|
||||
indexer.RebuildIndex();
|
||||
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
{
|
||||
ContentService = new TestContentService(TestFiles.umbraco_sort)
|
||||
},
|
||||
supportUnpublishedContent: true))
|
||||
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
|
||||
var s = (LuceneSearcher)searcher;
|
||||
var luceneSearcher = s.GetSearcher();
|
||||
@@ -69,25 +69,7 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
currentSort = sort;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void Test_Index_Type_With_German_Analyzer()
|
||||
//{
|
||||
// using (var luceneDir = new RAMDirectory())
|
||||
// {
|
||||
// var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir,
|
||||
// new GermanAnalyzer());
|
||||
// indexer.RebuildIndex();
|
||||
// var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private readonly TestContentService _contentService = new TestContentService();
|
||||
//private readonly TestMediaService _mediaService = new TestMediaService();
|
||||
//private static UmbracoExamineSearcher _searcher;
|
||||
//private static UmbracoContentIndexer _indexer;
|
||||
//private Lucene.Net.Store.Directory _luceneDir;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using UmbracoExamine;
|
||||
|
||||
namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
[TestFixture]
|
||||
public class UmbracoContentIndexerTests : ExamineBaseTest
|
||||
{
|
||||
[Test]
|
||||
public void Get_Serialized_Content_No_Published_Content()
|
||||
{
|
||||
var contentSet = new List<IContent>
|
||||
{
|
||||
Mock.Of<IContent>(c => c.Id == 1 && c.Path == "-1,1" && c.Published && c.Level == 1),
|
||||
Mock.Of<IContent>(c => c.Id == 2 && c.Path == "-1,2" && c.Published && c.Level == 1),
|
||||
Mock.Of<IContent>(c => c.Id == 3 && c.Path == "-1,3" && c.Published == false && c.Level == 1), // no
|
||||
Mock.Of<IContent>(c => c.Id == 4 && c.Path == "-1,4" && c.Published == false && c.Level == 1), // no
|
||||
|
||||
Mock.Of<IContent>(c => c.Id == 5 && c.Path == "-1,1,5" && c.Published && c.Level == 2),
|
||||
Mock.Of<IContent>(c => c.Id == 6 && c.Path == "-1,2,6" && c.Published == false && c.Level == 2), // no
|
||||
Mock.Of<IContent>(c => c.Id == 7 && c.Path == "-1,3,7" && c.Published && c.Level == 2), // no
|
||||
Mock.Of<IContent>(c => c.Id == 8 && c.Path == "-1,4,8" && c.Published && c.Level == 2), // no
|
||||
Mock.Of<IContent>(c => c.Id == 9 && c.Path == "-1,4,9" && c.Published && c.Level == 2), // no
|
||||
|
||||
Mock.Of<IContent>(c => c.Id == 10 && c.Path == "-1,1,5,10" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 15 && c.Path == "-1,1,5,15" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 11 && c.Path == "-1,2,6,11" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 16 && c.Path == "-1,2,6,16" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 12 && c.Path == "-1,3,7,12" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 17 && c.Path == "-1,3,7,17" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 13 && c.Path == "-1,4,8,13" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 18 && c.Path == "-1,4,8,18" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 14 && c.Path == "-1,4,9,14" && c.Published && c.Level == 3), // no
|
||||
Mock.Of<IContent>(c => c.Id == 19 && c.Path == "-1,4,9,19" && c.Published && c.Level == 3), // no
|
||||
};
|
||||
|
||||
//ensure the rest of the required values are populted
|
||||
foreach (var content in contentSet)
|
||||
{
|
||||
var mock = Mock.Get(content);
|
||||
mock.Setup(x => x.ContentType).Returns(Mock.Of<IContentType>(type => type.Icon == "hello"));
|
||||
}
|
||||
|
||||
contentSet.Sort((a, b) => Comparer<int>.Default.Compare(a.Level, b.Level));
|
||||
|
||||
var published = new HashSet<string>();
|
||||
|
||||
var result = UmbracoContentIndexer.GetSerializedContent(false, content => new XElement("test"), contentSet, published)
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, result.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Serialized_Content_With_Published_Content()
|
||||
{
|
||||
var contentSet = new List<IContent>
|
||||
{
|
||||
Mock.Of<IContent>(c => c.Id == 1 && c.Path == "-1,1" && c.Published && c.Level == 1),
|
||||
Mock.Of<IContent>(c => c.Id == 2 && c.Path == "-1,2" && c.Published && c.Level == 1),
|
||||
Mock.Of<IContent>(c => c.Id == 3 && c.Path == "-1,3" && c.Published == false && c.Level == 1),
|
||||
Mock.Of<IContent>(c => c.Id == 4 && c.Path == "-1,4" && c.Published == false && c.Level == 1),
|
||||
|
||||
Mock.Of<IContent>(c => c.Id == 5 && c.Path == "-1,1,5" && c.Published && c.Level == 2),
|
||||
Mock.Of<IContent>(c => c.Id == 6 && c.Path == "-1,2,6" && c.Published == false && c.Level == 2),
|
||||
Mock.Of<IContent>(c => c.Id == 7 && c.Path == "-1,3,7" && c.Published && c.Level == 2),
|
||||
Mock.Of<IContent>(c => c.Id == 8 && c.Path == "-1,4,8" && c.Published && c.Level == 2),
|
||||
Mock.Of<IContent>(c => c.Id == 9 && c.Path == "-1,4,9" && c.Published && c.Level == 2),
|
||||
|
||||
Mock.Of<IContent>(c => c.Id == 10 && c.Path == "-1,1,5,10" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 15 && c.Path == "-1,1,5,15" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 11 && c.Path == "-1,2,6,11" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 16 && c.Path == "-1,2,6,16" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 12 && c.Path == "-1,3,7,12" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 17 && c.Path == "-1,3,7,17" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 13 && c.Path == "-1,4,8,13" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 18 && c.Path == "-1,4,8,18" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 14 && c.Path == "-1,4,9,14" && c.Published && c.Level == 3),
|
||||
Mock.Of<IContent>(c => c.Id == 19 && c.Path == "-1,4,9,19" && c.Published && c.Level == 3),
|
||||
};
|
||||
|
||||
//ensure the rest of the required values are populted
|
||||
foreach (var content in contentSet)
|
||||
{
|
||||
var mock = Mock.Get(content);
|
||||
mock.Setup(x => x.ContentType).Returns(Mock.Of<IContentType>(type => type.Icon == "hello"));
|
||||
}
|
||||
|
||||
contentSet.Sort((a, b) => Comparer<int>.Default.Compare(a.Level, b.Level));
|
||||
|
||||
var published = new HashSet<string>();
|
||||
|
||||
var result = UmbracoContentIndexer.GetSerializedContent(true, content => new XElement("test"), contentSet, published)
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(19, result.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.80" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
|
||||
|
||||
@@ -69,22 +69,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.htmlEncode) {
|
||||
/** htmlEncode extension method for string */
|
||||
String.prototype.htmlEncode = function () {
|
||||
//create a in-memory div, set it's inner text(which jQuery automatically encodes)
|
||||
//then grab the encoded contents back out. The div never exists on the page.
|
||||
return $('<div/>').text(this).html();
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.htmlDecode) {
|
||||
/** htmlDecode extension method for string */
|
||||
String.prototype.htmlDecode = function () {
|
||||
return $('<div/>').html(this).text();
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
/** startsWith extension method for string */
|
||||
String.prototype.startsWith = function (str) {
|
||||
|
||||
@@ -172,6 +172,55 @@ angular.module("umbraco.directives")
|
||||
|
||||
});
|
||||
|
||||
// pin toolbar to top of screen if we have focus and it scrolls off the screen
|
||||
var pinToolbar = function () {
|
||||
|
||||
var _toolbar = $(editor.editorContainer).find(".mce-toolbar");
|
||||
var toolbarHeight = _toolbar.height();
|
||||
|
||||
var _tinyMce = $(editor.editorContainer);
|
||||
var tinyMceRect = _tinyMce[0].getBoundingClientRect();
|
||||
var tinyMceTop = tinyMceRect.top;
|
||||
var tinyMceBottom = tinyMceRect.bottom;
|
||||
var tinyMceWidth = tinyMceRect.width;
|
||||
|
||||
var _tinyMceEditArea = _tinyMce.find(".mce-edit-area");
|
||||
|
||||
// set padding in top of mce so the content does not "jump" up
|
||||
_tinyMceEditArea.css("padding-top", toolbarHeight);
|
||||
|
||||
if (tinyMceTop < 160 && ((160 + toolbarHeight) < tinyMceBottom)) {
|
||||
_toolbar
|
||||
.css("visibility", "visible")
|
||||
.css("position", "fixed")
|
||||
.css("top", "160px")
|
||||
.css("margin-top", "0")
|
||||
.css("width", tinyMceWidth);
|
||||
} else {
|
||||
_toolbar
|
||||
.css("visibility", "visible")
|
||||
.css("position", "absolute")
|
||||
.css("top", "auto")
|
||||
.css("margin-top", "0")
|
||||
.css("width", tinyMceWidth);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// unpin toolbar to top of screen
|
||||
var unpinToolbar = function() {
|
||||
|
||||
var _toolbar = $(editor.editorContainer).find(".mce-toolbar");
|
||||
var _tinyMce = $(editor.editorContainer);
|
||||
var _tinyMceEditArea = _tinyMce.find(".mce-edit-area");
|
||||
|
||||
// reset padding in top of mce so the content does not "jump" up
|
||||
_tinyMceEditArea.css("padding-top", "0");
|
||||
|
||||
_toolbar.css("position", "static");
|
||||
|
||||
};
|
||||
|
||||
//when we leave the editor (maybe)
|
||||
editor.on('blur', function (e) {
|
||||
editor.save();
|
||||
@@ -185,6 +234,9 @@ angular.module("umbraco.directives")
|
||||
scope.onBlur();
|
||||
}
|
||||
|
||||
unpinToolbar();
|
||||
$('.umb-panel-body').off('scroll', pinToolbar);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -196,6 +248,9 @@ angular.module("umbraco.directives")
|
||||
scope.onFocus();
|
||||
}
|
||||
|
||||
pinToolbar();
|
||||
$('.umb-panel-body').on('scroll', pinToolbar);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -207,6 +262,9 @@ angular.module("umbraco.directives")
|
||||
scope.onClick();
|
||||
}
|
||||
|
||||
pinToolbar();
|
||||
$('.umb-panel-body').on('scroll', pinToolbar);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -103,15 +103,15 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
* @description
|
||||
* This returns a promise with an underlying http call, it is a helper method to reduce
|
||||
* the amount of duplicate code needed to query http resources and automatically handle any
|
||||
* Http errors. See /docs/source/using-promises-resources.md
|
||||
* 500 Http server errors.
|
||||
*
|
||||
* @param {object} opts A mixed object which can either be a string representing the error message to be
|
||||
* returned OR an object containing either:
|
||||
* @param {object} opts A mixed object which can either be a `string` representing the error message to be
|
||||
* returned OR an `object` containing either:
|
||||
* { success: successCallback, errorMsg: errorMessage }
|
||||
* OR
|
||||
* { success: successCallback, error: errorCallback }
|
||||
* In both of the above, the successCallback must accept these parameters: data, status, headers, config
|
||||
* If using the errorCallback it must accept these parameters: data, status, headers, config
|
||||
* In both of the above, the successCallback must accept these parameters: `data`, `status`, `headers`, `config`
|
||||
* If using the errorCallback it must accept these parameters: `data`, `status`, `headers`, `config`
|
||||
* The success callback must return the data which will be resolved by the deferred object.
|
||||
* The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status }
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** Executed when the application starts, binds to events and set global state */
|
||||
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache',
|
||||
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache) {
|
||||
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService',
|
||||
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService) {
|
||||
|
||||
//This sets the default jquery ajax headers to include our csrf token, we
|
||||
// need to user the beforeSend method because our token changes per user/login so
|
||||
@@ -13,6 +13,11 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
|
||||
|
||||
/** Listens for authentication and checks if our required assets are loaded, if/once they are we'll broadcast a ready event */
|
||||
eventsService.on("app.authenticated", function(evt, data) {
|
||||
|
||||
//Removes all stored LocalStorage browser items - that may contain sensitive data
|
||||
//So if a machine or computer is shared and a new user logs in, we clear out the previous persons localStorage items
|
||||
localStorageService.clearAll();
|
||||
|
||||
assetsService._loadInitAssets().then(function() {
|
||||
appState.setGlobalState("isReady", true);
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<h4><localize key="prompt_unsavedChanges">You have unsaved changes</localize></h4>
|
||||
<p><localize key="prompt_unsavedChangesWarning">Are you sure you want to navigate away from this page? - you have unsaved changes</localize></p>
|
||||
|
||||
<button class="btn btn-warning" ng-click="discard(notification)"><localize key="prompt_discardChanges">Discard changes</localize></button>
|
||||
<button class="btn" ng-click="stay(notification)" umb-auto-focus><localize key="prompt_stay">Stay</localize></button>
|
||||
</div>
|
||||
<button class="btn" ng-click="discard(notification)"><localize key="prompt_discardChanges">Discard changes</localize></button>
|
||||
<button class="btn btn-success" ng-click="stay(notification)" umb-auto-focus><localize key="prompt_stay">Stay</localize></button>
|
||||
</div>
|
||||
|
||||
+3
-4
@@ -1,7 +1,7 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Overlays.MediaPickerController",
|
||||
function($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, $cookieStore, localizationService) {
|
||||
function ($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, localStorageService, localizationService) {
|
||||
|
||||
if (!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
|
||||
@@ -15,7 +15,7 @@ angular.module("umbraco")
|
||||
$scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
|
||||
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
|
||||
$scope.cropSize = dialogOptions.cropSize;
|
||||
$scope.lastOpenedNode = $cookieStore.get("umbLastOpenedMediaNodeId");
|
||||
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
|
||||
if ($scope.onlyImages) {
|
||||
$scope.acceptedFileTypes = mediaHelper
|
||||
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes);
|
||||
@@ -133,8 +133,7 @@ angular.module("umbraco")
|
||||
});
|
||||
$scope.currentFolder = folder;
|
||||
|
||||
// for some reason i cannot set cookies with cookieStore
|
||||
document.cookie = "umbLastOpenedMediaNodeId=" + folder.id;
|
||||
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -178,8 +178,6 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
|
||||
//share state
|
||||
editorState.set($scope.content);
|
||||
|
||||
dataTypeHelper.rebindChangedProperties($scope.content, data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -34,18 +34,24 @@
|
||||
fields: {},
|
||||
file: file
|
||||
}).progress(function (evt) {
|
||||
|
||||
// hack: in some browsers the progress event is called after success
|
||||
// this prevents the UI from going back to a uploading state
|
||||
if(vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") {
|
||||
|
||||
// set view state to uploading
|
||||
vm.state = 'uploading';
|
||||
// set view state to uploading
|
||||
vm.state = 'uploading';
|
||||
|
||||
// calculate progress in percentage
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
|
||||
// calculate progress in percentage
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
|
||||
|
||||
// set percentage property on file
|
||||
vm.zipFile.uploadProgress = progressPercentage;
|
||||
// set percentage property on file
|
||||
vm.zipFile.uploadProgress = progressPercentage;
|
||||
|
||||
// set uploading status on file
|
||||
vm.zipFile.uploadStatus = "uploading";
|
||||
// set uploading status on file
|
||||
vm.zipFile.uploadStatus = "uploading";
|
||||
|
||||
}
|
||||
|
||||
}).success(function (data, status, headers, config) {
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<div class="umb-package-list__item" ng-repeat="installedPackage in vm.installedPackages">
|
||||
|
||||
<div class="umb-package-list__item-icon">
|
||||
<i ng-if="!installedPackage.icon" class="icon-box"></i>
|
||||
<img ng-if="installedPackage.icon" ng-src="{{installedPackage.icon}}" />
|
||||
<i ng-if="!installedPackage.iconUrl" class="icon-box"></i>
|
||||
<img ng-if="installedPackage.iconUrl" ng-src="{{installedPackage.iconUrl}}" />
|
||||
</div>
|
||||
|
||||
<div class="umb-package-list__item-content">
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GoogleMapsController",
|
||||
function ($element, $rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) {
|
||||
|
||||
assetsService.loadJs('http://www.google.com/jsapi')
|
||||
assetsService.loadJs('https://www.google.com/jsapi')
|
||||
.then(function () {
|
||||
google.load("maps", "3",
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.TagsController",
|
||||
function ($rootScope, $scope, $log, assetsService, umbRequestHelper, angularHelper, $timeout, $element, $sanitize) {
|
||||
function ($rootScope, $scope, $log, assetsService, umbRequestHelper, angularHelper, $timeout, $element) {
|
||||
|
||||
var $typeahead;
|
||||
|
||||
@@ -41,7 +41,6 @@ angular.module("umbraco")
|
||||
|
||||
//Helper method to add a tag on enter or on typeahead select
|
||||
function addTag(tagToAdd) {
|
||||
tagToAdd = String(tagToAdd).htmlEncode();
|
||||
if (tagToAdd != null && tagToAdd.length > 0) {
|
||||
if ($scope.model.value.indexOf(tagToAdd) < 0) {
|
||||
$scope.model.value.push(tagToAdd);
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort>44319</IISExpressSSLPort>
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<IISExpressAnonymousAuthentication>enabled</IISExpressAnonymousAuthentication>
|
||||
<IISExpressWindowsAuthentication>disabled</IISExpressWindowsAuthentication>
|
||||
<IISExpressUseClassicPipelineMode>false</IISExpressUseClassicPipelineMode>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<MvcProjectUpgradeChecked>true</MvcProjectUpgradeChecked>
|
||||
@@ -56,7 +56,7 @@
|
||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||
<ConfigurationOverrideFile>
|
||||
</ConfigurationOverrideFile>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -127,20 +127,19 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.80.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.80\lib\net45\Examine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.4.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.4.5.0\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="ImageProcessor, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.1\lib\net45\ImageProcessor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor.Web, Version=4.6.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.Web.4.6.6.0\lib\net45\ImageProcessor.Web.dll</HintPath>
|
||||
<Reference Include="ImageProcessor.Web, Version=4.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.Web.4.8.0\lib\net45\ImageProcessor.Web.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
@@ -168,6 +167,9 @@
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.0\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@@ -651,6 +653,11 @@
|
||||
<None Include="Config\BaseRestExtensions.Release.config">
|
||||
<DependentUpon>BaseRestExtensions.config</DependentUpon>
|
||||
</None>
|
||||
<Content Include="Config\imageprocessor\security.config" />
|
||||
<Content Include="Config\imageprocessor\processing.config" />
|
||||
<Content Include="Config\imageprocessor\cache.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<None Include="Config\log4net.Release.config">
|
||||
<DependentUpon>log4net.config</DependentUpon>
|
||||
</None>
|
||||
@@ -2415,9 +2422,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7550</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7580</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7550</IISUrl>
|
||||
<IISUrl>http://localhost:7580</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="Application/NamespaceManager.js" PathNameAlias="UmbracoClient" Priority="0" />
|
||||
<umb:JsInclude ID="JsInclude3" runat="server" FilePath="ui/jquery.js" PathNameAlias="UmbracoClient" Priority="1" />
|
||||
<umb:JsInclude ID="JsInclude4" runat="server" FilePath="lib/jquery-migrate/jquery-migrate.min.js" PathNameAlias="UmbracoRoot" Priority="1" />
|
||||
<umb:JsInclude ID="JsInclude6" runat="server" FilePath="ui/base2.js" PathNameAlias="UmbracoClient" Priority="1" />
|
||||
<umb:JsInclude ID="JsInclude11" runat="server" FilePath="UI/knockout.js" PathNameAlias="UmbracoClient" Priority="3" />
|
||||
<umb:JsInclude ID="JsInclude12" runat="server" FilePath="UI/knockout.mapping.js" PathNameAlias="UmbracoClient" Priority="4" />
|
||||
|
||||
@@ -48,6 +48,15 @@ namespace Umbraco.Web.UI.Umbraco.Dashboard {
|
||||
/// </remarks>
|
||||
protected global::ClientDependency.Core.Controls.JsInclude JsInclude3;
|
||||
|
||||
/// <summary>
|
||||
/// JsInclude4 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::ClientDependency.Core.Controls.JsInclude JsInclude4;
|
||||
|
||||
/// <summary>
|
||||
/// JsInclude6 control.
|
||||
/// </summary>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
if(cfg != null)
|
||||
foreach (JProperty property in cfg.Properties())
|
||||
{
|
||||
var propertyValue = TemplateUtilities.CleanForXss(property.Value.ToString());
|
||||
var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
|
||||
attrs.Add(property.Name + "=\"" + propertyValue + "\"");
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
var cssVals = new List<string>();
|
||||
foreach (JProperty property in style.Properties())
|
||||
{
|
||||
var propertyValue = TemplateUtilities.CleanForXss(property.Value.ToString());
|
||||
var propertyValue = property.Value.ToString();
|
||||
if (string.IsNullOrWhiteSpace(propertyValue) == false)
|
||||
{
|
||||
cssVals.Add(property.Name + ":" + propertyValue + ";");
|
||||
@@ -84,7 +84,7 @@
|
||||
}
|
||||
|
||||
if (cssVals.Any())
|
||||
attrs.Add("style='" + string.Join(" ", cssVals) + "'");
|
||||
attrs.Add("style='" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "'");
|
||||
}
|
||||
|
||||
return new MvcHtmlString(string.Join(" ", attrs));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user