Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6
# Conflicts: # build/NuSpecs/UmbracoCms.nuspec # src/Umbraco.Tests/Umbraco.Tests.csproj
This commit is contained in:
@@ -33,9 +33,8 @@
|
||||
<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.5.0, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.7.1, 5.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.7.2, 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 -->
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,8 @@
|
||||
<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.5.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.0\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<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">
|
||||
<HintPath>..\packages\log4net-mediumtrust.2.0.0\lib\log4net.dll</HintPath>
|
||||
@@ -282,6 +282,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" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.0" targetFramework="net45" />
|
||||
<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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,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" />
|
||||
|
||||
@@ -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>
|
||||
]>
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
<Compile Include="Persistence\PetaPocoExpressionsTests.cs" />
|
||||
<Compile Include="Persistence\Repositories\RedirectUrlRepositoryTests.cs" />
|
||||
<Compile Include="Scheduling\DeployTest.cs" />
|
||||
<Compile Include="Routing\NiceUrlRoutesTests.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
|
||||
<Compile Include="TryConvertToTests.cs" />
|
||||
<Compile Include="Web\AngularIntegration\AngularAntiForgeryTests.cs" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -178,8 +178,6 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
|
||||
//share state
|
||||
editorState.set($scope.content);
|
||||
|
||||
dataTypeHelper.rebindChangedProperties($scope.content, data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -135,11 +135,11 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.5.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.0\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<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.7.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.Web.4.7.1\lib\net45\ImageProcessor.Web.dll</HintPath>
|
||||
<Reference Include="ImageProcessor.Web, Version=4.7.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.Web.4.7.2\lib\net45\ImageProcessor.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -654,7 +654,9 @@
|
||||
</None>
|
||||
<Content Include="Config\imageprocessor\security.config" />
|
||||
<Content Include="Config\imageprocessor\processing.config" />
|
||||
<Content Include="Config\imageprocessor\cache.config" />
|
||||
<Content Include="Config\imageprocessor\cache.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<None Include="Config\log4net.Release.config">
|
||||
<DependentUpon>log4net.config</DependentUpon>
|
||||
</None>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<package id="ClientDependency-Mvc5" version="1.8.0.0" targetFramework="net45" />
|
||||
<package id="dotless" version="1.4.1.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.0" targetFramework="net45" />
|
||||
<package id="ImageProcessor.Web" version="4.7.1" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.1" targetFramework="net45" />
|
||||
<package id="ImageProcessor.Web" version="4.7.2" targetFramework="net45" />
|
||||
<package id="ImageProcessor.Web.Config" version="2.3.0" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
|
||||
@@ -46,9 +46,7 @@ namespace Umbraco.Web.Models
|
||||
{
|
||||
var route = umbracoContext == null
|
||||
? null // for tests only
|
||||
: umbracoContext.ContentCache.GetRouteById(contentId); // cached
|
||||
|
||||
if (route != null && route.StartsWith("err/")) route = null;
|
||||
: umbracoContext.ContentCache.GetRouteById(contentId); // may be cached
|
||||
|
||||
var domainHelper = new DomainHelper(domainService);
|
||||
IDomain domain;
|
||||
@@ -73,7 +71,7 @@ namespace Umbraco.Web.Models
|
||||
}
|
||||
else
|
||||
{
|
||||
// if content is published then we have a (cached) route
|
||||
// if content is published then we have a route
|
||||
// from which we can figure out the domain
|
||||
|
||||
var pos = route.IndexOf('/');
|
||||
|
||||
@@ -2,11 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
@@ -18,7 +16,6 @@ using umbraco.BusinessLogic;
|
||||
using umbraco.presentation.preview;
|
||||
using Umbraco.Core.Services;
|
||||
using GlobalSettings = umbraco.GlobalSettings;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
@@ -83,7 +80,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
&& DomainHelper.ExistsDomainInPath(umbracoContext.Application.Services.DomainService.GetAll(false), content.Path, domainRootNodeId) == false;
|
||||
|
||||
if (deepest)
|
||||
_routesCache.Store(content.Id, route);
|
||||
_routesCache.Store(content.Id, route, true); // trusted route
|
||||
}
|
||||
|
||||
public virtual string GetRouteById(UmbracoContext umbracoContext, bool preview, int contentId)
|
||||
@@ -102,38 +99,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
if (route == null)
|
||||
return null;
|
||||
|
||||
// find the content back, detect routes collisions: we should find ourselves back,
|
||||
// else it means that another content with "higher priority" is sharing the same route.
|
||||
// perf impact:
|
||||
// - non-colliding, adds one complete "by route" lookup, only on the first time a url is computed (then it's cached anyways)
|
||||
// - colliding, adds one "by route" lookup, the first time the url is computed, then one dictionary looked each time it is computed again
|
||||
// assuming no collisions, the impact is one complete "by route" lookup the first time each url is computed
|
||||
//
|
||||
// U4-9121 - this lookup is too expensive when computing a large amount of urls on a front-end (eg menu)
|
||||
// ... thinking about moving the lookup out of the path into its own async task, so we are not reporting errors
|
||||
// in the back-office anymore, but at least we are not polluting the cache
|
||||
// instead, refactored DeterminedIdByRoute to stop using XPath, with a 16x improvement according to benchmarks
|
||||
// will it be enough?
|
||||
// cache the route BUT do NOT trust it as it can be a colliding route
|
||||
// meaning if we GetRouteById again, we'll get it from cache, but it
|
||||
// won't be used for inbound routing
|
||||
if (preview == false)
|
||||
_routesCache.Store(contentId, route, false);
|
||||
|
||||
var loopId = preview ? 0 : _routesCache.GetNodeId(route); // might be cached already in case of collision
|
||||
if (loopId == 0)
|
||||
{
|
||||
var content = DetermineIdByRoute(umbracoContext, preview, route, GlobalSettings.HideTopLevelNodeFromPath);
|
||||
|
||||
// add the other route to cache so next time we have it already
|
||||
if (content != null && preview == false)
|
||||
AddToCacheIfDeepestRoute(umbracoContext, content, route);
|
||||
|
||||
loopId = content == null ? 0 : content.Id; // though... 0 here would be quite weird?
|
||||
}
|
||||
|
||||
// cache if we have a route and not previewing and it's not a colliding route
|
||||
// (the result of DetermineRouteById is always the deepest route)
|
||||
if (/*route != null &&*/ preview == false && loopId == contentId)
|
||||
_routesCache.Store(contentId, route);
|
||||
|
||||
// return route if no collision, else report collision
|
||||
return loopId == contentId ? route : ("err/" + loopId);
|
||||
return route;
|
||||
}
|
||||
|
||||
IPublishedContent DetermineIdByRoute(UmbracoContext umbracoContext, bool preview, string route, bool hideTopLevelNode)
|
||||
@@ -149,18 +121,25 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
//check if we can find the node in our xml cache
|
||||
var id = NavigateRoute(umbracoContext, preview, startNodeId, path, hideTopLevelNode);
|
||||
if (id > 0) return GetById(umbracoContext, preview, id);
|
||||
return id > 0 ? GetById(umbracoContext, preview, id) : null;
|
||||
}
|
||||
|
||||
// if hideTopLevelNodePath is true then for url /foo we looked for /*/foo
|
||||
// but maybe that was the url of a non-default top-level node, so we also
|
||||
// have to look for /foo (see note in ApplyHideTopLevelNodeFromPath).
|
||||
if (hideTopLevelNode && path.Length > 1 && path.IndexOf('/', 1) < 0)
|
||||
private static XmlElement GetXmlElementChildWithLowestSortOrder(XmlNode element)
|
||||
{
|
||||
XmlElement elt = null;
|
||||
var min = int.MaxValue;
|
||||
foreach (var n in element.ChildNodes)
|
||||
{
|
||||
var id2 = NavigateRoute(umbracoContext, preview, startNodeId, path, false);
|
||||
if (id2 > 0) return GetById(umbracoContext, preview, id2);
|
||||
}
|
||||
var e = n as XmlElement;
|
||||
if (e == null) continue;
|
||||
|
||||
return null;
|
||||
var sortOrder = int.Parse(e.GetAttribute("sortOrder"));
|
||||
if (sortOrder >= min) continue;
|
||||
|
||||
min = sortOrder;
|
||||
elt = e;
|
||||
}
|
||||
return elt;
|
||||
}
|
||||
|
||||
private int NavigateRoute(UmbracoContext umbracoContext, bool preview, int startNodeId, string path, bool hideTopLevelNode)
|
||||
@@ -177,17 +156,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
return elt == null ? -1 : startNodeId;
|
||||
}
|
||||
|
||||
elt = null;
|
||||
var min = int.MaxValue;
|
||||
foreach (var e in xml.DocumentElement.ChildNodes.OfType<XmlElement>())
|
||||
{
|
||||
var sortOrder = int.Parse(e.GetAttribute("sortOrder"));
|
||||
if (sortOrder < min)
|
||||
{
|
||||
min = sortOrder;
|
||||
elt = e;
|
||||
}
|
||||
}
|
||||
elt = GetXmlElementChildWithLowestSortOrder(xml.DocumentElement);
|
||||
return elt == null ? -1 : int.Parse(elt.GetAttribute("id"));
|
||||
}
|
||||
|
||||
@@ -201,12 +170,19 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
if (hideTopLevelNode && startNodeId <= 0)
|
||||
{
|
||||
foreach (var e in elt.ChildNodes.OfType<XmlElement>())
|
||||
//Don't use OfType<T> or Cast<T>, this is critical code, all ChildNodes are XmlElement so explicitly cast
|
||||
// https://gist.github.com/Shazwazza/04e2e5642a316f4a87e52dada2901198
|
||||
foreach (var n in elt.ChildNodes)
|
||||
{
|
||||
var e = n as XmlElement;
|
||||
if (e == null) continue;
|
||||
|
||||
var id = NavigateElementRoute(e, urlParts);
|
||||
if (id > 0) return id;
|
||||
}
|
||||
return -1;
|
||||
|
||||
if (urlParts.Length > 1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return NavigateElementRoute(elt, urlParts);
|
||||
@@ -224,8 +200,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
while (found && i < urlParts.Length)
|
||||
{
|
||||
found = false;
|
||||
foreach (var child in elt.ChildNodes.OfType<XmlElement>())
|
||||
//Don't use OfType<T> or Cast<T>, this is critical code, all ChildNodes are XmlElement so explicitly cast
|
||||
// https://gist.github.com/Shazwazza/04e2e5642a316f4a87e52dada2901198
|
||||
var sortOrder = -1;
|
||||
foreach (var o in elt.ChildNodes)
|
||||
{
|
||||
var child = o as XmlElement;
|
||||
if (child == null) continue;
|
||||
|
||||
var noNode = UseLegacySchema
|
||||
? child.Name != "node"
|
||||
: child.GetAttributeNode("isDoc") == null;
|
||||
@@ -233,8 +215,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
if (child.GetAttribute("urlName") != urlParts[i]) continue;
|
||||
|
||||
found = true;
|
||||
|
||||
var so = int.Parse(child.GetAttribute("sortOrder"));
|
||||
if (sortOrder >= 0 && so >= sortOrder) continue;
|
||||
|
||||
sortOrder = so;
|
||||
elt = child;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -243,7 +229,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
string DetermineRouteById(UmbracoContext umbracoContext, bool preview, int contentId)
|
||||
{
|
||||
var elt = GetXml(umbracoContext, preview).GetElementById(contentId.ToString(CultureInfo.InvariantCulture));
|
||||
var xml = GetXml(umbracoContext, preview);
|
||||
var elt = xml.GetElementById(contentId.ToString(CultureInfo.InvariantCulture));
|
||||
if (elt == null) return null;
|
||||
|
||||
var domainHelper = GetDomainHelper(umbracoContext.Application.Services.DomainService);
|
||||
@@ -270,7 +257,18 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
|
||||
if (hasDomains == false && GlobalSettings.HideTopLevelNodeFromPath)
|
||||
ApplyHideTopLevelNodeFromPath(umbracoContext, eltId, eltParentId, pathParts);
|
||||
{
|
||||
if (eltParentId == -1)
|
||||
{
|
||||
var rootNode = GetXmlElementChildWithLowestSortOrder(xml.DocumentElement);
|
||||
if (rootNode != null && rootNode == elt)
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// assemble the route
|
||||
pathParts.Reverse();
|
||||
@@ -280,30 +278,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
return route;
|
||||
}
|
||||
|
||||
static void ApplyHideTopLevelNodeFromPath(UmbracoContext umbracoContext, int nodeId, int parentId, IList<string> pathParts)
|
||||
{
|
||||
// in theory if hideTopLevelNodeFromPath is true, then there should be only once
|
||||
// top-level node, or else domains should be assigned. but for backward compatibility
|
||||
// we add this check - we look for the document matching "/" and if it's not us, then
|
||||
// we do not hide the top level path
|
||||
// it has to be taken care of in GetByRoute too so if
|
||||
// "/foo" fails (looking for "/*/foo") we try also "/foo".
|
||||
// this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but
|
||||
// that's the way it works pre-4.10 and we try to be backward compat for the time being
|
||||
if (parentId == -1)
|
||||
{
|
||||
var rootNode = umbracoContext.ContentCache.GetByRoute("/", true);
|
||||
if (rootNode == null)
|
||||
throw new Exception("Failed to get node at /.");
|
||||
if (rootNode.Id == nodeId) // remove only if we're the default node
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathParts.RemoveAt(pathParts.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XPath Strings
|
||||
|
||||
@@ -83,10 +83,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identified.</param>
|
||||
/// <param name="route">The route.</param>
|
||||
public void Store(int nodeId, string route)
|
||||
/// <param name="trust">A value indicating whether the value can be trusted for inbound routing.</param>
|
||||
public void Store(int nodeId, string route, bool trust)
|
||||
{
|
||||
_routes.AddOrUpdate(nodeId, i => route, (i, s) => route);
|
||||
_nodeIds.AddOrUpdate(route, i => nodeId, (i, s) => nodeId);
|
||||
if (trust)
|
||||
_nodeIds.AddOrUpdate(route, i => nodeId, (i, s) => nodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,15 +121,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
public void ClearNode(int nodeId)
|
||||
{
|
||||
if (!_routes.ContainsKey(nodeId)) return;
|
||||
|
||||
string key;
|
||||
if (!_routes.TryGetValue(nodeId, out key)) return;
|
||||
|
||||
int val;
|
||||
_nodeIds.TryRemove(key, out val);
|
||||
string val2;
|
||||
_routes.TryRemove(nodeId, out val2);
|
||||
string route;
|
||||
if (_routes.TryRemove(nodeId, out route))
|
||||
{
|
||||
int id;
|
||||
_nodeIds.TryRemove(route, out id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -65,14 +65,6 @@ namespace Umbraco.Web.Routing
|
||||
return null;
|
||||
}
|
||||
|
||||
if (route.StartsWith("err/"))
|
||||
{
|
||||
LogHelper.Debug<DefaultUrlProvider>(
|
||||
"Page with nodeId={0} has a colliding url with page with nodeId={1}.",
|
||||
() => id, () => route.Substring(4));
|
||||
return "#err-" + route.Substring(4);
|
||||
}
|
||||
|
||||
var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService);
|
||||
|
||||
// extract domainUri and path
|
||||
@@ -115,9 +107,6 @@ namespace Umbraco.Web.Routing
|
||||
return null;
|
||||
}
|
||||
|
||||
if (route.StartsWith("err/"))
|
||||
return null;
|
||||
|
||||
var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService);
|
||||
|
||||
// extract domainUri and path
|
||||
|
||||
@@ -67,6 +67,32 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
#region Public
|
||||
|
||||
/// <summary>
|
||||
/// Tries to route the request.
|
||||
/// </summary>
|
||||
internal bool TryRouteRequest()
|
||||
{
|
||||
// disabled - is it going to change the routing?
|
||||
//_pcr.OnPreparing();
|
||||
|
||||
FindDomain();
|
||||
if (_pcr.IsRedirect) return false;
|
||||
if (_pcr.HasPublishedContent) return true;
|
||||
FindPublishedContent();
|
||||
if (_pcr.IsRedirect) return false;
|
||||
|
||||
// don't handle anything - we just want to ensure that we find the content
|
||||
//HandlePublishedContent();
|
||||
//FindTemplate();
|
||||
//FollowExternalRedirect();
|
||||
//HandleWildcardDomains();
|
||||
|
||||
// disabled - we just want to ensure that we find the content
|
||||
//_pcr.OnPrepared();
|
||||
|
||||
return _pcr.HasPublishedContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the request.
|
||||
/// </summary>
|
||||
|
||||
@@ -295,8 +295,7 @@ namespace Umbraco.Web.Routing
|
||||
private static bool IsNotRoute(string route)
|
||||
{
|
||||
// null if content not found
|
||||
// err/- if collision or anomaly or ...
|
||||
return route == null || route.StartsWith("err/");
|
||||
return route == null;
|
||||
}
|
||||
|
||||
// gets a value indicating whether server is 'slave'
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
@@ -62,34 +65,45 @@ namespace Umbraco.Web.Routing
|
||||
{
|
||||
urls.Add(ui.Text("content", "getUrlException", umbracoContext.Security.CurrentUser));
|
||||
}
|
||||
else if (url.StartsWith("#err-"))
|
||||
else
|
||||
{
|
||||
// route error, report
|
||||
var id = int.Parse(url.Substring(5));
|
||||
var o = umbracoContext.ContentCache.GetById(id);
|
||||
string s;
|
||||
if (o == null)
|
||||
// test for collisions
|
||||
var uri = new Uri(url.TrimEnd('/'), UriKind.RelativeOrAbsolute);
|
||||
if (uri.IsAbsoluteUri == false) uri = uri.MakeAbsolute(UmbracoContext.Current.CleanedUmbracoUrl);
|
||||
var pcr = new PublishedContentRequest(uri, UmbracoContext.Current.RoutingContext, UmbracoConfig.For.UmbracoSettings().WebRouting, s => Roles.Provider.GetRolesForUser(s));
|
||||
pcr.Engine.TryRouteRequest();
|
||||
|
||||
if (pcr.HasPublishedContent == false)
|
||||
{
|
||||
s = "(unknown)";
|
||||
urls.Add(ui.Text("content", "routeError", "(error)", umbracoContext.Security.CurrentUser));
|
||||
}
|
||||
else if (pcr.PublishedContent.Id != content.Id)
|
||||
{
|
||||
var o = pcr.PublishedContent;
|
||||
string s;
|
||||
if (o == null)
|
||||
{
|
||||
s = "(unknown)";
|
||||
}
|
||||
else
|
||||
{
|
||||
var l = new List<string>();
|
||||
while (o != null)
|
||||
{
|
||||
l.Add(o.Name);
|
||||
o = o.Parent;
|
||||
}
|
||||
l.Reverse();
|
||||
s = "/" + string.Join("/", l) + " (id=" + pcr.PublishedContent.Id + ")";
|
||||
|
||||
}
|
||||
urls.Add(ui.Text("content", "routeError", s, umbracoContext.Security.CurrentUser));
|
||||
}
|
||||
else
|
||||
{
|
||||
var l = new List<string>();
|
||||
while (o != null)
|
||||
{
|
||||
l.Add(o.Name);
|
||||
o = o.Parent;
|
||||
}
|
||||
l.Reverse();
|
||||
s = "/" + string.Join("/", l) + " (id=" + id + ")";
|
||||
|
||||
urls.Add(url);
|
||||
urls.AddRange(urlProvider.GetOtherUrls(content.Id));
|
||||
}
|
||||
urls.Add(ui.Text("content", "routeError", s, umbracoContext.Security.CurrentUser));
|
||||
}
|
||||
else
|
||||
{
|
||||
urls.Add(url);
|
||||
urls.AddRange(urlProvider.GetOtherUrls(content.Id));
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user