From 08a8e6b816e0c44777698b0168aaf3a25c50b87a Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 14 Jan 2013 00:48:54 -1100 Subject: [PATCH 01/18] U4-497 : Razor errors should be completely silent when UmbracoDebug=false. Optionally requires macroErrors.config to define macro error behaviour. See http://issues.umbraco.org/issue/U4-497. --- src/Umbraco.Web/umbraco.presentation/macro.cs | 133 +++++++++++---- .../umbraco/templateControls/Macro.cs | 1 + .../RazorCore/RazorMacroEngine.cs | 6 +- .../MacroErrorBehaviour.cs | 23 +++ src/umbraco.businesslogic/MacroErrorConfig.cs | 157 ++++++++++++++++++ .../umbraco.businesslogic.csproj | 2 + .../businesslogic/events/EventArgs.cs | 10 +- 7 files changed, 292 insertions(+), 40 deletions(-) create mode 100644 src/umbraco.businesslogic/MacroErrorBehaviour.cs create mode 100644 src/umbraco.businesslogic/MacroErrorConfig.cs diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 2b2d2f9a16..5a59a3ad29 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -18,17 +18,16 @@ using System.Xml.Xsl; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; -using Umbraco.Web; using Umbraco.Web.Macros; using Umbraco.Web.Templates; using umbraco.BusinessLogic; -using umbraco.BusinessLogic.Utils; +using umbraco.businesslogic; +using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.macro; using umbraco.cms.businesslogic.member; using umbraco.DataLayer; using umbraco.NodeFactory; using umbraco.presentation.templateControls; -using umbraco.presentation.xslt.Exslt; using Content = umbraco.cms.businesslogic.Content; using Macro = umbraco.cms.businesslogic.macro.Macro; @@ -429,8 +428,24 @@ namespace umbraco { renderFailed = true; Exceptions.Add(e); - LogHelper.WarnWithException("Error loading userControl (" + Model.TypeName + ")", true, e); - macroControl = new LiteralControl("Error loading userControl '" + Model.TypeName + "'"); + LogHelper.WarnWithException("Error loading userControl (" + Model.TypeName + ")", true, e); + + // Invoke any error handlers for this macro + OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.TypeName, Exception = e}); + + // Check how to handle the error for this macro + var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); + switch (macroErrorConfig.Behaviour) + { + case MacroErrorBehaviour.Inline: + macroControl = new LiteralControl("Error loading userControl '" + Model.TypeName + "'"); + break; + case MacroErrorBehaviour.Silent: + macroControl = new LiteralControl(""); + break; + case MacroErrorBehaviour.Throw: + throw; + } break; } case (int)MacroTypes.CustomControl: @@ -451,11 +466,23 @@ namespace umbraco LogHelper.WarnWithException("Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + Model.TypeName + "'", true, e); - - macroControl = - new LiteralControl("Error loading customControl (Assembly: " + Model.TypeAssembly + - ", Type: '" + - Model.TypeName + "'"); + + // Invoke any error handlers for this macro + OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.TypeAssembly, Exception = e}); + + // Check how to handle the error for this macro + var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); + switch (macroErrorConfig.Behaviour) + { + case MacroErrorBehaviour.Inline: + macroControl = new LiteralControl("Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + Model.TypeName + "'"); + break; + case MacroErrorBehaviour.Silent: + macroControl = new LiteralControl(""); + break; + case MacroErrorBehaviour.Throw: + throw; + } break; } case (int)MacroTypes.XSLT: @@ -487,24 +514,22 @@ namespace umbraco true, e); - var result = - new LiteralControl("Error loading MacroEngine script (file: " + ScriptFile + ")"); - - /* - string args = "
    "; - foreach(object key in attributes.Keys) - args += "
  • " + key.ToString() + ": " + attributes[key] + "
  • "; - - foreach (object key in pageElements.Keys) - args += "
  • " + key.ToString() + ": " + pageElements[key] + "
  • "; - - args += "
"; - - result.Text += args; - */ - - macroControl = result; + // Invoke any error handlers for this macro + OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = ScriptFile, Exception = e}); + // Check how to handle the error for this macro + var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); + switch (macroErrorConfig.Behaviour) + { + case MacroErrorBehaviour.Inline: + macroControl = new LiteralControl("Error loading MacroEngine script (file: " + ScriptFile + ")"); + break; + case MacroErrorBehaviour.Silent: + macroControl = new LiteralControl(""); + break; + case MacroErrorBehaviour.Throw: + throw; + } break; } default: @@ -801,7 +826,25 @@ namespace umbraco { Exceptions.Add(e); LogHelper.WarnWithException("Error loading XSLT " + Model.Xslt, true, e); - return new LiteralControl("Error reading XSLT file: \\xslt\\" + XsltFile); + Control macroControl = null; + + // Invoke any error handlers for this macro + OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.Xslt, Exception = e}); + + // Check how to handle the error for this macro + var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); + switch (macroErrorConfig.Behaviour) + { + case MacroErrorBehaviour.Inline: + macroControl = new LiteralControl("Error reading XSLT file: \\xslt\\" + XsltFile); + break; + case MacroErrorBehaviour.Silent: + macroControl = new LiteralControl(""); + break; + case MacroErrorBehaviour.Throw: + throw; + } + return macroControl; } } } @@ -1505,7 +1548,7 @@ namespace umbraco } if (!File.Exists(IOHelper.MapPath(userControlPath))) - return new LiteralControl(string.Format("UserControl {0} does not exist.", fileName)); + throw new UmbracoException(string.Format("UserControl {0} does not exist.", fileName)); var oControl = (UserControl)new UserControl().LoadControl(userControlPath); @@ -1531,11 +1574,7 @@ namespace umbraco catch (Exception e) { LogHelper.WarnWithException(string.Format("Error creating usercontrol ({0})", fileName), true, e); - - return new LiteralControl( - string.Format( - "
Error creating control ({0}).
Maybe file doesn't exists or the usercontrol has a cache directive, which is not allowed! See the tracestack for more information!
", - fileName)); + throw; } } @@ -1802,5 +1841,31 @@ namespace umbraco value = false; return false; } + + #region Events + + /// + /// The macro error event handler. + /// + public delegate void ErrorEventHandler(object sender, MacroErrorEventArgs e); + + /// + /// Occurs when a macro error is raised. + /// + public static event ErrorEventHandler Error; + + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected virtual void OnError(MacroErrorEventArgs e) + { + if (Error != null) + { + Error(this, e); + } + } + + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs index dc94b66cd8..db27764b80 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs @@ -183,6 +183,7 @@ namespace umbraco.presentation.templateControls System.Web.HttpContext.Current.Trace.Warn("Template", "Result of macro " + tempMacro.Name + " is null"); } catch (Exception ee) { System.Web.HttpContext.Current.Trace.Warn("Template", "Error adding macro " + tempMacro.Name, ee); + throw; } } } diff --git a/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs b/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs index e30d8c5dca..83304f7ab2 100644 --- a/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs +++ b/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs @@ -171,11 +171,7 @@ namespace umbraco.MacroEngines Success = false; ResultException = exception; HttpContext.Current.Trace.Warn("umbracoMacro", string.Format("Error Loading Razor Script (file: {0}) {1} {2}", macro.Name, exception.Message, exception.StackTrace)); - var loading = string.Format("
Error loading Razor Script {0}
", macro.ScriptName); - if (GlobalSettings.DebugMode) - loading = loading + exception.Message; - loading = loading + "
"; - return loading; + throw; } } diff --git a/src/umbraco.businesslogic/MacroErrorBehaviour.cs b/src/umbraco.businesslogic/MacroErrorBehaviour.cs new file mode 100644 index 0000000000..314401fd07 --- /dev/null +++ b/src/umbraco.businesslogic/MacroErrorBehaviour.cs @@ -0,0 +1,23 @@ +namespace umbraco.businesslogic +{ + public enum MacroErrorBehaviour + { + /// + /// Default umbraco behavior - show an inline error within the + /// macro but allow the page to continue rendering. + /// + Inline, + + /// + /// Silently eat the error and do not display the offending macro. + /// + Silent, + + /// + /// Throw an exception which can be caught by the global error handler + /// defined in Application_OnError. If no such error handler is defined + /// then you'll see the Yellow Screen Of Death (YSOD) error page. + /// + Throw + } +} diff --git a/src/umbraco.businesslogic/MacroErrorConfig.cs b/src/umbraco.businesslogic/MacroErrorConfig.cs new file mode 100644 index 0000000000..47a0c1ccb2 --- /dev/null +++ b/src/umbraco.businesslogic/MacroErrorConfig.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Web; +using System.Xml.Linq; +using umbraco.IO; + +namespace umbraco.businesslogic +{ + /// + /// umbraco.BusinessLogic.MacroErrorConfig provides access to the macro error configuration in umbraco. + /// This configuration defines how handle macro errors: + /// - Show error within macro as text (default and current Umbraco 'normal' behavior) + /// - Suppress error and hide macro + /// - Throw an exception and invoke the global error handler (if one is defined, if not you'll get a YSOD) + /// These options can be set on a per macro basis based on the macro name using regexes. + /// + public class MacroErrorConfig + { + private const string CacheKey = "MacroErrorCache"; + internal const string MacroErrorConfigFileName = "macroerrors.config"; + private static string _macroErrorConfig; + private static readonly object Locker = new object(); + + /// + /// gets/sets the macroerrors.config file path + /// + /// + /// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath + /// + internal static string MacroErrorConfigFilePath + { + get + { + if (string.IsNullOrWhiteSpace(_macroErrorConfig)) + { + _macroErrorConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + MacroErrorConfigFileName); + } + return _macroErrorConfig; + } + set { _macroErrorConfig = value; } + } + + /// + /// The cache storage for macro error configuration. + /// + private static List MacroErrorConfiguration + { + get + { + //ensure cache exists + EnsureCache(); + return HttpRuntime.Cache[CacheKey] as List; + } + set + { + HttpRuntime.Cache.Insert(CacheKey, value); + } + } + + /// + /// Gets or sets the regex match for this macro error - we match on the macro name. + /// + /// The regular expression used to match the macro name. + public string Regex { get; set; } + + /// + /// Gets or sets the desired behaviour when a matching macro causes an error. See + /// for definitions. + /// + /// Macro error behaviour enum. + public MacroErrorBehaviour Behaviour { get; set; } + + /// + /// Gets the matching configuration by regular expression matching the macro name. + /// + /// The macro name that is faulting. + /// A MacroErrorConfig instance + public static MacroErrorConfig getForMacroName(string macroName) + { + var matchingMacroErrorConfig = MacroErrorConfiguration.Find(mec => (new Regex(mec.Regex, RegexOptions.IgnoreCase).IsMatch(macroName))); + if (matchingMacroErrorConfig == null) + { + // Return an instance that allows the default behaviour of Umbraco to continue. + return new MacroErrorConfig { Regex = ".*", Behaviour = MacroErrorBehaviour.Inline }; + } + return matchingMacroErrorConfig; + } + + /// + /// Read all MacroErrorConfig data and store it in cache. + /// + private static void EnsureCache() + { + // Don't read the configuration file if the cache is not null + if (HttpRuntime.Cache[CacheKey] != null) + return; + + lock (Locker) + { + if (HttpRuntime.Cache[CacheKey] == null) + { + var list = new List(); + + LoadXml(doc => + { + foreach (var addElement in doc.Root.Elements("add")) + { + var regex = addElement.Attribute("regex"); + var behaviour = addElement.Attribute("behaviour"); + if (regex == null) + { + throw new ArgumentException("macroErrors.config has an entry with no regex attribute defined. Please use regex=\".*\" if you wish to match all macros."); + } + if (behaviour == null) + { + throw new ArgumentException("macroErrors.config has an entry with no behaviour attribute defined. Please define behaviour with one of 'inline', 'silent' or 'throw'."); + } + MacroErrorBehaviour behaviourEnum; + try + { + behaviourEnum = (MacroErrorBehaviour)Enum.Parse(typeof(MacroErrorBehaviour), behaviour.Value, true); + } + catch (Exception) + { + throw new ArgumentException("macroErrors.config has an entry with a behaviour attribute value that is not supported. Please define behaviour with one of 'inline', 'silent' or 'throw'."); + } + + list.Add(new MacroErrorConfig + { + Regex = regex.Value, + Behaviour = behaviourEnum + }); + } + }); + + MacroErrorConfiguration = list; + } + } + } + + internal static void LoadXml(Action callback) + { + lock (Locker) + { + var doc = File.Exists(MacroErrorConfigFilePath) + ? XDocument.Load(MacroErrorConfigFilePath) + : XDocument.Parse(""); + if (doc.Root != null) + { + callback.Invoke(doc); + } + } + } + } +} diff --git a/src/umbraco.businesslogic/umbraco.businesslogic.csproj b/src/umbraco.businesslogic/umbraco.businesslogic.csproj index ca64da53c1..5e895b3d01 100644 --- a/src/umbraco.businesslogic/umbraco.businesslogic.csproj +++ b/src/umbraco.businesslogic/umbraco.businesslogic.csproj @@ -149,6 +149,8 @@ + + diff --git a/src/umbraco.cms/businesslogic/events/EventArgs.cs b/src/umbraco.cms/businesslogic/events/EventArgs.cs index 3514065cee..fe4a59ee3d 100644 --- a/src/umbraco.cms/businesslogic/events/EventArgs.cs +++ b/src/umbraco.cms/businesslogic/events/EventArgs.cs @@ -61,5 +61,13 @@ namespace umbraco.cms.businesslogic { { public bool CancelChildren { get; set; } } - + + // Provides information on the macro that caused an error + public class MacroErrorEventArgs : System.EventArgs + { + public string Name { get; set; } + public string Alias { get; set; } + public string File { get; set; } + public Exception Exception { get; set; } + } } From 41258104f6c5f716754ed02a455726717cf51b5a Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Wed, 16 Jan 2013 00:45:18 -1100 Subject: [PATCH 02/18] U4-497 - Razor errors should be completely silent when UmbracoDebug=false. Modified implementation to have a single global setting in UmbracoSettings.config which can now be overridden when the umbraco.macro.Error event is handled on a per-macro basis if desired. --- .../Configuration/UmbracoSettings.cs | 34 ++++ .../MacroErrorBehaviour.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../config/umbracoSettings.Release.config | 8 + .../config/umbracoSettings.config | 7 + src/Umbraco.Web/umbraco.presentation/macro.cs | 37 +++-- src/umbraco.businesslogic/MacroErrorConfig.cs | 157 ------------------ src/umbraco.businesslogic/UmbracoSettings.cs | 18 +- .../umbraco.businesslogic.csproj | 2 - .../businesslogic/events/EventArgs.cs | 24 +++ 10 files changed, 108 insertions(+), 182 deletions(-) rename src/{umbraco.businesslogic => Umbraco.Core}/MacroErrorBehaviour.cs (92%) delete mode 100644 src/umbraco.businesslogic/MacroErrorConfig.cs diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs index beab6537b3..4702771492 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs @@ -1220,6 +1220,40 @@ namespace Umbraco.Core.Configuration } } + private static MacroErrorBehaviour? _macroErrorBehaviour; + + /// + /// This configuration setting defines how to handle macro errors: + /// - Inline - Show error within macro as text (default and current Umbraco 'normal' behavior) + /// - Silent - Suppress error and hide macro + /// - Throw - Throw an exception and invoke the global error handler (if one is defined, if not you'll get a YSOD) + /// + /// MacroErrorBehaviour enum defining how to handle macro errors. + public static MacroErrorBehaviour MacroErrorBehaviour + { + get + { + if (_macroErrorBehaviour == null) + { + try + { + var behaviour = MacroErrorBehaviour.Inline; + var value = GetKey("/settings/content/MacroErrors"); + if (value != null) + { + Enum.TryParse(value, true, out behaviour); + } + _macroErrorBehaviour = behaviour; + } + catch (Exception ex) + { + LogHelper.Error("Could not load /settings/content/MacroErrors from umbracosettings.config", ex); + _macroErrorBehaviour = MacroErrorBehaviour.Inline; + } + } + return _macroErrorBehaviour.Value; + } + } /// /// Configuration regarding webservices diff --git a/src/umbraco.businesslogic/MacroErrorBehaviour.cs b/src/Umbraco.Core/MacroErrorBehaviour.cs similarity index 92% rename from src/umbraco.businesslogic/MacroErrorBehaviour.cs rename to src/Umbraco.Core/MacroErrorBehaviour.cs index 314401fd07..50d9faa19c 100644 --- a/src/umbraco.businesslogic/MacroErrorBehaviour.cs +++ b/src/Umbraco.Core/MacroErrorBehaviour.cs @@ -1,4 +1,4 @@ -namespace umbraco.businesslogic +namespace Umbraco.Core { public enum MacroErrorBehaviour { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 672bed94a7..692db70412 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -69,6 +69,7 @@ + diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index d70b455d11..66f10198bf 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -86,6 +86,14 @@ false + + + inline diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index 372777126a..66ce17b300 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -81,6 +81,13 @@ 1800 + + inline diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 5a59a3ad29..63dd86e547 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -21,7 +21,6 @@ using Umbraco.Core.Logging; using Umbraco.Web.Macros; using Umbraco.Web.Templates; using umbraco.BusinessLogic; -using umbraco.businesslogic; using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.macro; using umbraco.cms.businesslogic.member; @@ -431,11 +430,12 @@ namespace umbraco LogHelper.WarnWithException("Error loading userControl (" + Model.TypeName + ")", true, e); // Invoke any error handlers for this macro - OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.TypeName, Exception = e}); + var macroErrorEventArgs = new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.TypeName, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour}; + OnError(macroErrorEventArgs); - // Check how to handle the error for this macro - var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); - switch (macroErrorConfig.Behaviour) + // Check how to handle the error for this macro. + // (note the error event above may have changed the default behaviour as defined in settings) + switch (macroErrorEventArgs.Behaviour) { case MacroErrorBehaviour.Inline: macroControl = new LiteralControl("Error loading userControl '" + Model.TypeName + "'"); @@ -468,11 +468,12 @@ namespace umbraco ", Type: '" + Model.TypeName + "'", true, e); // Invoke any error handlers for this macro - OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.TypeAssembly, Exception = e}); + var macroErrorEventArgs = new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.TypeAssembly, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour}; + OnError(macroErrorEventArgs); - // Check how to handle the error for this macro - var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); - switch (macroErrorConfig.Behaviour) + // Check how to handle the error for this macro. + // (note the error event above may have changed the default behaviour as defined in settings) + switch (macroErrorEventArgs.Behaviour) { case MacroErrorBehaviour.Inline: macroControl = new LiteralControl("Error loading customControl (Assembly: " + Model.TypeAssembly + ", Type: '" + Model.TypeName + "'"); @@ -515,11 +516,12 @@ namespace umbraco e); // Invoke any error handlers for this macro - OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = ScriptFile, Exception = e}); + var macroErrorEventArgs = new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = ScriptFile, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour}; + OnError(macroErrorEventArgs); - // Check how to handle the error for this macro - var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); - switch (macroErrorConfig.Behaviour) + // Check how to handle the error for this macro. + // (note the error event above may have changed the default behaviour as defined in settings) + switch (macroErrorEventArgs.Behaviour) { case MacroErrorBehaviour.Inline: macroControl = new LiteralControl("Error loading MacroEngine script (file: " + ScriptFile + ")"); @@ -829,11 +831,12 @@ namespace umbraco Control macroControl = null; // Invoke any error handlers for this macro - OnError(new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.Xslt, Exception = e}); + var macroErrorEventArgs = new MacroErrorEventArgs {Name = Model.Name, Alias = Model.Alias, File = Model.Xslt, Exception = e, Behaviour = UmbracoSettings.MacroErrorBehaviour}; + OnError(macroErrorEventArgs); - // Check how to handle the error for this macro - var macroErrorConfig = MacroErrorConfig.getForMacroName(Model.Name); - switch (macroErrorConfig.Behaviour) + // Check how to handle the error for this macro. + // (note the error event above may have changed the default behaviour as defined in settings) + switch (macroErrorEventArgs.Behaviour) { case MacroErrorBehaviour.Inline: macroControl = new LiteralControl("Error reading XSLT file: \\xslt\\" + XsltFile); diff --git a/src/umbraco.businesslogic/MacroErrorConfig.cs b/src/umbraco.businesslogic/MacroErrorConfig.cs deleted file mode 100644 index 47a0c1ccb2..0000000000 --- a/src/umbraco.businesslogic/MacroErrorConfig.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using System.Web; -using System.Xml.Linq; -using umbraco.IO; - -namespace umbraco.businesslogic -{ - /// - /// umbraco.BusinessLogic.MacroErrorConfig provides access to the macro error configuration in umbraco. - /// This configuration defines how handle macro errors: - /// - Show error within macro as text (default and current Umbraco 'normal' behavior) - /// - Suppress error and hide macro - /// - Throw an exception and invoke the global error handler (if one is defined, if not you'll get a YSOD) - /// These options can be set on a per macro basis based on the macro name using regexes. - /// - public class MacroErrorConfig - { - private const string CacheKey = "MacroErrorCache"; - internal const string MacroErrorConfigFileName = "macroerrors.config"; - private static string _macroErrorConfig; - private static readonly object Locker = new object(); - - /// - /// gets/sets the macroerrors.config file path - /// - /// - /// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath - /// - internal static string MacroErrorConfigFilePath - { - get - { - if (string.IsNullOrWhiteSpace(_macroErrorConfig)) - { - _macroErrorConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + MacroErrorConfigFileName); - } - return _macroErrorConfig; - } - set { _macroErrorConfig = value; } - } - - /// - /// The cache storage for macro error configuration. - /// - private static List MacroErrorConfiguration - { - get - { - //ensure cache exists - EnsureCache(); - return HttpRuntime.Cache[CacheKey] as List; - } - set - { - HttpRuntime.Cache.Insert(CacheKey, value); - } - } - - /// - /// Gets or sets the regex match for this macro error - we match on the macro name. - /// - /// The regular expression used to match the macro name. - public string Regex { get; set; } - - /// - /// Gets or sets the desired behaviour when a matching macro causes an error. See - /// for definitions. - /// - /// Macro error behaviour enum. - public MacroErrorBehaviour Behaviour { get; set; } - - /// - /// Gets the matching configuration by regular expression matching the macro name. - /// - /// The macro name that is faulting. - /// A MacroErrorConfig instance - public static MacroErrorConfig getForMacroName(string macroName) - { - var matchingMacroErrorConfig = MacroErrorConfiguration.Find(mec => (new Regex(mec.Regex, RegexOptions.IgnoreCase).IsMatch(macroName))); - if (matchingMacroErrorConfig == null) - { - // Return an instance that allows the default behaviour of Umbraco to continue. - return new MacroErrorConfig { Regex = ".*", Behaviour = MacroErrorBehaviour.Inline }; - } - return matchingMacroErrorConfig; - } - - /// - /// Read all MacroErrorConfig data and store it in cache. - /// - private static void EnsureCache() - { - // Don't read the configuration file if the cache is not null - if (HttpRuntime.Cache[CacheKey] != null) - return; - - lock (Locker) - { - if (HttpRuntime.Cache[CacheKey] == null) - { - var list = new List(); - - LoadXml(doc => - { - foreach (var addElement in doc.Root.Elements("add")) - { - var regex = addElement.Attribute("regex"); - var behaviour = addElement.Attribute("behaviour"); - if (regex == null) - { - throw new ArgumentException("macroErrors.config has an entry with no regex attribute defined. Please use regex=\".*\" if you wish to match all macros."); - } - if (behaviour == null) - { - throw new ArgumentException("macroErrors.config has an entry with no behaviour attribute defined. Please define behaviour with one of 'inline', 'silent' or 'throw'."); - } - MacroErrorBehaviour behaviourEnum; - try - { - behaviourEnum = (MacroErrorBehaviour)Enum.Parse(typeof(MacroErrorBehaviour), behaviour.Value, true); - } - catch (Exception) - { - throw new ArgumentException("macroErrors.config has an entry with a behaviour attribute value that is not supported. Please define behaviour with one of 'inline', 'silent' or 'throw'."); - } - - list.Add(new MacroErrorConfig - { - Regex = regex.Value, - Behaviour = behaviourEnum - }); - } - }); - - MacroErrorConfiguration = list; - } - } - } - - internal static void LoadXml(Action callback) - { - lock (Locker) - { - var doc = File.Exists(MacroErrorConfigFilePath) - ? XDocument.Load(MacroErrorConfigFilePath) - : XDocument.Parse(""); - if (doc.Root != null) - { - callback.Invoke(doc); - } - } - } - } -} diff --git a/src/umbraco.businesslogic/UmbracoSettings.cs b/src/umbraco.businesslogic/UmbracoSettings.cs index 22133c3945..c7db9fdeb1 100644 --- a/src/umbraco.businesslogic/UmbracoSettings.cs +++ b/src/umbraco.businesslogic/UmbracoSettings.cs @@ -1,11 +1,7 @@ using System; -using System.Diagnostics; -using System.IO; using System.Linq; -using System.Web; -using System.Web.Caching; using System.Xml; -using umbraco.BusinessLogic; +using Umbraco.Core; using System.Collections.Generic; using umbraco.MacroEngines; @@ -554,6 +550,18 @@ namespace umbraco get { return Umbraco.Core.Configuration.UmbracoSettings.ResolveUrlsFromTextString; } } + /// + /// This configuration setting defines how to handle macro errors: + /// - Inline - Show error within macro as text (default and current Umbraco 'normal' behavior) + /// - Silent - Suppress error and hide macro + /// - Throw - Throw an exception and invoke the global error handler (if one is defined, if not you'll get a YSOD) + /// + /// MacroErrorBehaviour enum defining how to handle macro errors. + public static MacroErrorBehaviour MacroErrorBehaviour + { + get { return Umbraco.Core.Configuration.UmbracoSettings.MacroErrorBehaviour; } + } + /// /// Configuration regarding webservices /// diff --git a/src/umbraco.businesslogic/umbraco.businesslogic.csproj b/src/umbraco.businesslogic/umbraco.businesslogic.csproj index 5e895b3d01..ca64da53c1 100644 --- a/src/umbraco.businesslogic/umbraco.businesslogic.csproj +++ b/src/umbraco.businesslogic/umbraco.businesslogic.csproj @@ -149,8 +149,6 @@ - - diff --git a/src/umbraco.cms/businesslogic/events/EventArgs.cs b/src/umbraco.cms/businesslogic/events/EventArgs.cs index fe4a59ee3d..87942060f6 100644 --- a/src/umbraco.cms/businesslogic/events/EventArgs.cs +++ b/src/umbraco.cms/businesslogic/events/EventArgs.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Umbraco.Core; using umbraco.cms.businesslogic.member; using umbraco.cms.businesslogic.web; @@ -65,9 +66,32 @@ namespace umbraco.cms.businesslogic { // Provides information on the macro that caused an error public class MacroErrorEventArgs : System.EventArgs { + /// + /// Name of the faulting macro. + /// public string Name { get; set; } + + /// + /// Alias of the faulting macro. + /// public string Alias { get; set; } + + /// + /// Filename of the faulting macro. + /// public string File { get; set; } + + /// + /// Exception raised. + /// public Exception Exception { get; set; } + + /// + /// Gets or sets the desired behaviour when a matching macro causes an error. See + /// for definitions. By setting this in your event + /// you can override the default behaviour defined in UmbracoSettings.config. + /// + /// Macro error behaviour enum. + public MacroErrorBehaviour Behaviour { get; set; } } } From 0f6c41679c2ec09fce4c93004b2bb20b1306dd96 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 1 Mar 2013 06:49:45 -0100 Subject: [PATCH 03/18] Added tag Release-6.0.1 for changeset 92410e141d9c --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 7c3e21acf3..ea826350a2 100644 --- a/.hgtags +++ b/.hgtags @@ -26,3 +26,4 @@ ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta 56015ac26f5ab60e3c61b1d09075297b660afa07 Release-6.0.0-RC 1719fbd857f28b376639ac2aa0abada0ef2e7560 Release-6.0.0 e02f5aebb87e3f07d27376647756caa9762931d8 Release-4.11.4 +92410e141d9c41498dbc72a6a59ab1990747d74a Release-6.0.1 From 2e7c26fcc0307bea36d29adc0e75ff1f3f80427f Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 1 Mar 2013 06:49:59 -0100 Subject: [PATCH 04/18] Closing branch 6.0.1 From d2d1843e03e5297e9914a4eeceda4cf45eb012bd Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 8 Apr 2013 07:03:57 -0200 Subject: [PATCH 05/18] Fix default branch --- src/Umbraco.Web/umbraco.presentation/macro.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 2f4bdf9820..aea5e4de03 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -31,6 +31,7 @@ using umbraco.NodeFactory; using umbraco.presentation.templateControls; using Content = umbraco.cms.businesslogic.Content; using Macro = umbraco.cms.businesslogic.macro.Macro; +using MacroErrorEventArgs = Umbraco.Core.Events.MacroErrorEventArgs; namespace umbraco { From c12f9d027205aa5d0dfadf1e990138613ab0e77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Skyldahl=20S=C3=B8rensen?= Date: Wed, 17 Apr 2013 14:03:54 -0200 Subject: [PATCH 06/18] Optimization for issue: U4-1187 Url: http://issues.umbraco.org/issue/U4-1187 Added assembly filtering, to stop scanning of third party assemblies that doesn't reference the types we are looking for. this limits the amount of possible missing references we encounter when checking against the types --- src/Umbraco.Core/TypeFinder.cs | 178 ++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 71 deletions(-) diff --git a/src/Umbraco.Core/TypeFinder.cs b/src/Umbraco.Core/TypeFinder.cs index 6b7627e257..2630133a62 100644 --- a/src/Umbraco.Core/TypeFinder.cs +++ b/src/Umbraco.Core/TypeFinder.cs @@ -2,23 +2,18 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Linq.Expressions; using System.Reflection; using System.Security; using System.Text; using System.Threading; using System.Web; using System.Web.Compilation; -using System.Web.Hosting; -using Umbraco.Core.Configuration; using Umbraco.Core.IO; namespace Umbraco.Core { - //TODO: Get the App_Code stuff in here from the old one /// @@ -27,7 +22,6 @@ namespace Umbraco.Core /// public static class TypeFinder { - private static readonly ConcurrentBag LocalFilteredAssemblyCache = new ConcurrentBag(); private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim(); private static ReadOnlyCollection _allAssemblies = null; @@ -86,8 +80,7 @@ namespace Umbraco.Core } //now set the _allAssemblies - _allAssemblies = new ReadOnlyCollection(assemblies); - + _allAssemblies = new ReadOnlyCollection(assemblies); } catch (InvalidOperationException e) { @@ -100,8 +93,8 @@ namespace Umbraco.Core } return _allAssemblies; - } - + } + /// /// Returns only assemblies found in the bin folder that have been loaded into the app domain. /// @@ -111,7 +104,6 @@ namespace Umbraco.Core /// internal static IEnumerable GetBinAssemblies() { - if (_binFolderAssemblies == null) { using (new WriteLock(Locker)) @@ -143,7 +135,8 @@ namespace Umbraco.Core { try { - var foundAssembly = safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile()); + var foundAssembly = + safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile()); if (foundAssembly != null) { binFolderAssemblies.Add(foundAssembly); @@ -162,7 +155,7 @@ namespace Umbraco.Core } } return _binFolderAssemblies; - } + } /// /// Return a list of found local Assemblies excluding the known assemblies we don't want to scan @@ -181,7 +174,7 @@ namespace Umbraco.Core assemblies.ForEach(LocalFilteredAssemblyCache.Add); } return LocalFilteredAssemblyCache; - } + } /// /// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter @@ -190,18 +183,18 @@ namespace Umbraco.Core /// /// private static IEnumerable GetFilteredAssemblies( - IEnumerable excludeFromResults = null, + IEnumerable excludeFromResults = null, string[] exclusionFilter = null) { if (excludeFromResults == null) excludeFromResults = new List(); if (exclusionFilter == null) - exclusionFilter = new string[] { }; + exclusionFilter = new string[] {}; return GetAllAssemblies() .Where(x => !excludeFromResults.Contains(x) - && !x.GlobalAssemblyCache - && !exclusionFilter.Any(f => x.FullName.StartsWith(f))); + && !x.GlobalAssemblyCache + && !exclusionFilter.Any(f => x.FullName.StartsWith(f))); } /// @@ -211,42 +204,42 @@ namespace Umbraco.Core /// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match /// internal static readonly string[] KnownAssemblyExclusionFilter = new[] - { - "mscorlib,", - "System.", - "Antlr3.", - "Autofac.", - "Autofac,", - "Castle.", - "ClientDependency.", - "DataAnnotationsExtensions.", - "DataAnnotationsExtensions,", - "Dynamic,", - "HtmlDiff,", - "Iesi.Collections,", - "log4net,", - "Microsoft.", - "Newtonsoft.", - "NHibernate.", - "NHibernate,", - "NuGet.", - "RouteDebugger,", - "SqlCE4Umbraco,", - "umbraco.datalayer,", - "umbraco.interfaces,", - "umbraco.providers,", - "Umbraco.Web.UI,", - "umbraco.webservices", - "Lucene.", - "Examine,", - "Examine.", - "ServiceStack.", - "MySql.", - "HtmlAgilityPack.", - "TidyNet.", - "ICSharpCode.", - "CookComputing." - }; + { + "mscorlib,", + "System.", + "Antlr3.", + "Autofac.", + "Autofac,", + "Castle.", + "ClientDependency.", + "DataAnnotationsExtensions.", + "DataAnnotationsExtensions,", + "Dynamic,", + "HtmlDiff,", + "Iesi.Collections,", + "log4net,", + "Microsoft.", + "Newtonsoft.", + "NHibernate.", + "NHibernate,", + "NuGet.", + "RouteDebugger,", + "SqlCE4Umbraco,", + "umbraco.datalayer,", + "umbraco.interfaces,", + "umbraco.providers,", + "Umbraco.Web.UI,", + "umbraco.webservices", + "Lucene.", + "Examine,", + "Examine.", + "ServiceStack.", + "MySql.", + "HtmlAgilityPack.", + "TidyNet.", + "ICSharpCode.", + "CookComputing." + }; public static IEnumerable FindClassesOfTypeWithAttribute() where TAttribute : Attribute @@ -260,13 +253,19 @@ namespace Umbraco.Core return FindClassesOfTypeWithAttribute(assemblies, true); } - public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses) + public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies, + bool onlyConcreteClasses) where TAttribute : Attribute { if (assemblies == null) throw new ArgumentNullException("assemblies"); + // a assembly cant contain types that are assignable to a type it doesn't reference + assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(typeof (T), assemblies); + // a assembly cant contain types with a attribute it doesn't reference + assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(typeof (TAttribute), assemblies); + var l = new List(); - foreach(var a in assemblies) + foreach (var a in assemblies) { var types = from t in GetTypesWithFormattedException(a) where !t.IsInterface @@ -325,7 +324,7 @@ namespace Umbraco.Core public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses) where T : Attribute { - return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses); + return FindClassesWithAttribute(typeof (T), assemblies, onlyConcreteClasses); } /// @@ -335,23 +334,58 @@ namespace Umbraco.Core /// The assemblies. /// if set to true only concrete classes. /// - public static IEnumerable FindClassesWithAttribute(Type type, IEnumerable assemblies, bool onlyConcreteClasses) + public static IEnumerable FindClassesWithAttribute(Type type, IEnumerable assemblies, + bool onlyConcreteClasses) { if (assemblies == null) throw new ArgumentNullException("assemblies"); if (!TypeHelper.IsTypeAssignableFrom(type)) throw new ArgumentException("The type specified: " + type + " is not an Attribute type"); + // a assembly cant contain types with a attribute it doesn't reference + assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(type, assemblies); var l = new List(); foreach (var a in assemblies) { var types = from t in GetTypesWithFormattedException(a) - where !t.IsInterface && t.GetCustomAttributes(type, false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) - select t; + where + !t.IsInterface && t.GetCustomAttributes(type, false).Any() && + (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) + select t; l.AddRange(types); } return l; } + /// + /// Removes assemblies that doesn't reference the assembly of the type we are looking for. + /// + /// + /// + /// + private static IEnumerable RemoveAssembliesThatDontReferenceAssemblyOfType(Type type, + IEnumerable assemblies) + { + // Avoid scanning assembly if it doesn't contain a reference to the assembly containing the type we are looking for + // to the assembly containing the attribute we are looking for + var assemblyNameOfType = type.Assembly.GetName().Name; + + return assemblies + .Where(assembly => assembly == type.Assembly + || HasReferenceToAssemblyWithName(assembly, assemblyNameOfType)).ToList(); + } + /// + /// checks if the assembly has a reference with the same name as the expected assembly name. + /// + /// + /// + /// + private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName) + { + return assembly + .GetReferencedAssemblies() + .Select(a => a.Name) + .Contains(expectedAssemblyName, StringComparer.Ordinal); + } /// /// Finds the classes with attribute. @@ -376,9 +410,8 @@ namespace Umbraco.Core return FindClassesWithAttribute(GetAssembliesWithKnownExclusions()); } - #region Private methods - + /// /// Gets a collection of assignables of type T from a collection of assemblies /// @@ -388,20 +421,26 @@ namespace Umbraco.Core /// private static IEnumerable GetAssignablesFromType(IEnumerable assemblies, bool onlyConcreteClasses) { - return GetTypes(typeof(T), assemblies, onlyConcreteClasses); + return GetTypes(typeof (T), assemblies, onlyConcreteClasses); } - private static IEnumerable GetTypes(Type assignTypeFrom, IEnumerable assemblies, bool onlyConcreteClasses) + private static IEnumerable GetTypes(Type assignTypeFrom, IEnumerable assemblies, + bool onlyConcreteClasses) { + // a assembly cant contain types that are assignable to a type it doesn't reference + assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(assignTypeFrom, assemblies); + var l = new List(); foreach (var a in assemblies) { var types = from t in GetTypesWithFormattedException(a) - where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) + where + !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && + (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) select t; l.AddRange(types); } - return l; + return l; } private static IEnumerable GetTypesWithFormattedException(Assembly a) @@ -420,15 +459,12 @@ namespace Umbraco.Core sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:"); foreach (var loaderException in ex.LoaderExceptions.WhereNotNull()) { - sb.AppendLine("Exception: " + loaderException.ToString()); + sb.AppendLine("Exception: " + loaderException); } throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString()); } } #endregion - - - } -} +} \ No newline at end of file From 09a4e33f3f81daa346d958c7687cae385579298d Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 25 Apr 2013 11:20:21 -0200 Subject: [PATCH 07/18] Closing again.. From f5553bcc06e099c42b24f961617dc16a5692e5a7 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 10 Jun 2013 18:05:07 +0200 Subject: [PATCH 08/18] Create README.md --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..f8815f30eb --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +Umbraco CMS +=========== +![](http://download-codeplex.sec.s-msft.com/Download?ProjectName=umbraco&DownloadId=55656) + +## Watch a five minute introduction video ## + +[http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco](http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco) + +## Umbraco - the simple, flexible and friendly ASP.NET CMS ## + +**More than 155,000 sites trust Umbraco** +For the first time on the Microsoft platform a free user and developer friendly cms that makes it quick and easy to create websites - or a breeze to build complex web applications. umbraco got award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 110,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. +[More info at http://umbraco.org +Forums](http://umbraco.org) + +We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions area on CodePlex will be for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). + +## Contribute to Umbraco ## + +If you want to contribute back to Umbraco you should check out our [guide to contributing](http://our.umbraco.org/contribute). + +## Submitting Issues ## + +Another way you can contribute to Umbraco is by providing issue reports, for information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature). + +To view existing issues please visit [http://issues.umbraco.org](http://issues.umbraco.org) From a6eaec9ecbaad404103aaca464cecf8e68a51af5 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 10 Jun 2013 19:09:03 +0300 Subject: [PATCH 09/18] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f8815f30eb..e16aa47db5 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ Umbraco CMS **More than 155,000 sites trust Umbraco** For the first time on the Microsoft platform a free user and developer friendly cms that makes it quick and easy to create websites - or a breeze to build complex web applications. umbraco got award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 110,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. -[More info at http://umbraco.org -Forums](http://umbraco.org) +[More info at http://umbraco.org](http://umbraco.org) +## Forums ## We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions area on CodePlex will be for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). ## Contribute to Umbraco ## From 5fd90e1c135c950e8398e6f9bf0e43880c80ac90 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 10 Jun 2013 19:17:37 +0300 Subject: [PATCH 10/18] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index e16aa47db5..5e7cb63499 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ Umbraco CMS =========== -![](http://download-codeplex.sec.s-msft.com/Download?ProjectName=umbraco&DownloadId=55656) - ## Watch a five minute introduction video ## -[http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco](http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco) +[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco) ## Umbraco - the simple, flexible and friendly ASP.NET CMS ## From 53b31a5c1b4f0bfc7048db5b4994f03e15cb8702 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 12 Jun 2013 10:04:31 +0200 Subject: [PATCH 11/18] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 5e7cb63499..c898c77de7 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ Umbraco CMS For the first time on the Microsoft platform a free user and developer friendly cms that makes it quick and easy to create websites - or a breeze to build complex web applications. umbraco got award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 110,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. [More info at http://umbraco.org](http://umbraco.org) +## Downloading ## +The downloadable Umbraco releases live at [http://our.umbraco.org/contribute/releases](Our Umbraco). + ## Forums ## We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions area on CodePlex will be for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). From 0815842640f59b20438551693669e40a9108d104 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 12 Jun 2013 11:10:18 +0300 Subject: [PATCH 12/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c898c77de7..399792bcef 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The If you want to contribute back to Umbraco you should check out our [guide to contributing](http://our.umbraco.org/contribute). -## Submitting Issues ## +## Found a bug? ## Another way you can contribute to Umbraco is by providing issue reports, for information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature). From 458e61e049dc732dbaeaaeea76d02e07f03d0323 Mon Sep 17 00:00:00 2001 From: dpen2000 Date: Wed, 12 Jun 2013 14:45:41 +0200 Subject: [PATCH 13/18] Update README.md Fix link to Umbraco releases page --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 399792bcef..54393e6baf 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ For the first time on the Microsoft platform a free user and developer friendly [More info at http://umbraco.org](http://umbraco.org) ## Downloading ## -The downloadable Umbraco releases live at [http://our.umbraco.org/contribute/releases](Our Umbraco). +The downloadable Umbraco releases live at [http://our.umbraco.org/contribute/releases](http://our.umbraco.org/contribute/releases). ## Forums ## We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions area on CodePlex will be for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). From 73ac2c03092e24de0e84802d2def6b70881cf84b Mon Sep 17 00:00:00 2001 From: Jeavon Date: Wed, 12 Jun 2013 15:34:26 +0200 Subject: [PATCH 14/18] Update README.md Readme.md corrections and updates --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 54393e6baf..b1dc21ee7e 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,16 @@ Umbraco CMS ## Umbraco - the simple, flexible and friendly ASP.NET CMS ## -**More than 155,000 sites trust Umbraco** -For the first time on the Microsoft platform a free user and developer friendly cms that makes it quick and easy to create websites - or a breeze to build complex web applications. umbraco got award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 110,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. -[More info at http://umbraco.org](http://umbraco.org) +**More than 177,000 sites trust Umbraco** +More than 177,000 sites trust Umbraco +For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. +[More info at http://umbraco.com](http://umbraco.com) ## Downloading ## The downloadable Umbraco releases live at [http://our.umbraco.org/contribute/releases](http://our.umbraco.org/contribute/releases). ## Forums ## -We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions area on CodePlex will be for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). +We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions group on [Google Groups](https://groups.google.com/forum/#!forum/umbraco-dev) is for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). ## Contribute to Umbraco ## From 95eb00a81cfaa1fb23da946467255a9d06168306 Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Wed, 12 Jun 2013 18:24:54 +0200 Subject: [PATCH 15/18] Update README.md Updating link and formatting --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b1dc21ee7e..f842afd3c2 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,20 @@ Umbraco CMS ## Umbraco - the simple, flexible and friendly ASP.NET CMS ## -**More than 177,000 sites trust Umbraco** -More than 177,000 sites trust Umbraco -For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. -[More info at http://umbraco.com](http://umbraco.com) +**More than 177,000 sites trust Umbraco** + +For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. + +Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales. + +To view more examples please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies) ## Downloading ## + The downloadable Umbraco releases live at [http://our.umbraco.org/contribute/releases](http://our.umbraco.org/contribute/releases). ## Forums ## + We have a forum running on [http://our.umbraco.org](http://our.umbraco.org). The discussions group on [Google Groups](https://groups.google.com/forum/#!forum/umbraco-dev) is for discussions on developing the core, and not on Umbraco-implementations or extensions in general. For those topics, please use [http://our.umbraco.org](http://our.umbraco.org). ## Contribute to Umbraco ## From f5121bd183b3a852782eb7f7d252dead80c17f51 Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Tue, 18 Jun 2013 09:35:33 -0400 Subject: [PATCH 16/18] Fix for U4-2384. Author not changed to current user when a node is copied. --- src/Umbraco.Core/Services/ContentService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 1254bb295c..0236be227c 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -862,7 +862,8 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - content.WriterId = userId; + copy.CreatorId = userId; + content.WriterId = userId; // Typo? repository.AddOrUpdate(copy); uow.Commit(); From 5e2c3a0a8b32ba6cb8667154d8d47ed20be90b2a Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Tue, 18 Jun 2013 10:38:08 -0400 Subject: [PATCH 17/18] Fixed a type on content copy. --- src/Umbraco.Core/Services/ContentService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 0236be227c..fda3d71d31 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -862,8 +862,10 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { + // Update the create author and last edit author copy.CreatorId = userId; - content.WriterId = userId; // Typo? + copy.WriterId = userId; + repository.AddOrUpdate(copy); uow.Commit(); From 7c6aee17e90d4b59a29cbcabf915475510c072c7 Mon Sep 17 00:00:00 2001 From: Darren Ferguson Date: Wed, 19 Jun 2013 13:02:58 +0100 Subject: [PATCH 18/18] Remove obsolete messages from member class I've removed the obsolete methods from the member class because many of the suggested alternatives don't work. and some require a lot of configuration to get working. Also, the member methods return Members - so they are not obsolete if you want a reference to a member, you can choose to use System membership if you want, but for custom properties and groups you need to fallback to the Umbraco API, so these shouldn't be obsolete! :) --- .../businesslogic/member/Member.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/umbraco.cms/businesslogic/member/Member.cs b/src/umbraco.cms/businesslogic/member/Member.cs index 3738890789..fba3c5510b 100644 --- a/src/umbraco.cms/businesslogic/member/Member.cs +++ b/src/umbraco.cms/businesslogic/member/Member.cs @@ -91,7 +91,7 @@ namespace umbraco.cms.businesslogic.member /// /// Note: is ressource intensive, use with care. /// - [Obsolete("Use System.Web.Security.Membership.GetAllUsers()")] + public static Member[] GetAll { get @@ -146,13 +146,13 @@ namespace umbraco.cms.businesslogic.member /// /// The first letter /// - [Obsolete("Use System.Web.Security.Membership.FindUsersByName(string letter)")] + public static Member[] getMemberFromFirstLetter(char letter) { return GetMemberByName(letter.ToString(), true); } - [Obsolete("Use System.Web.Security.Membership.FindUsersByName(string letter)")] + public static Member[] GetMemberByName(string usernameToMatch, bool matchByNameInsteadOfLogin) { string field = matchByNameInsteadOfLogin ? "umbracoNode.text" : "cmsMember.loginName"; @@ -184,7 +184,7 @@ namespace umbraco.cms.businesslogic.member /// Member type /// The umbraco usercontext /// The new member - [Obsolete("Use System.Web.Security.Membership.CreateUser")] + public static Member MakeNew(string Name, MemberType mbt, User u) { return MakeNew(Name, "", "", mbt, u); @@ -199,7 +199,7 @@ namespace umbraco.cms.businesslogic.member /// The umbraco usercontext /// The email of the user /// The new member - [Obsolete("Use System.Web.Security.Membership.CreateUser")] + public static Member MakeNew(string Name, string Email, MemberType mbt, User u) { return MakeNew(Name, "", Email, mbt, u); @@ -213,7 +213,7 @@ namespace umbraco.cms.businesslogic.member /// The umbraco usercontext /// The email of the user /// The new member - [Obsolete("Use System.Web.Security.Membership.CreateUser")] + public static Member MakeNew(string Name, string LoginName, string Email, MemberType mbt, User u) { var loginName = (!String.IsNullOrEmpty(LoginName)) ? LoginName : Name; @@ -265,7 +265,7 @@ namespace umbraco.cms.businesslogic.member /// /// The unique Loginname /// The member with the specified loginname - null if no Member with the login exists - [Obsolete("Use System.Web.Security.Membership.GetUser")] + public static Member GetMemberFromLoginName(string loginName) { if (String.IsNullOrEmpty(loginName)) @@ -298,7 +298,7 @@ namespace umbraco.cms.businesslogic.member /// /// The email of the member /// The member with the specified email - null if no Member with the email exists - [Obsolete("Use System.Web.Security.Membership.GetUserNameByEmail")] + public static Member GetMemberFromEmail(string email) { if (string.IsNullOrEmpty(email)) @@ -326,7 +326,7 @@ namespace umbraco.cms.businesslogic.member /// Member login /// Member password /// The member with the credentials - null if none exists - [Obsolete("Log members in via the standard Forms Authentiaction login")] + public static Member GetMemberFromLoginNameAndPassword(string loginName, string password) { if (IsMember(loginName)) @@ -677,7 +677,7 @@ namespace umbraco.cms.businesslogic.member /// /// Deltes the current member /// - [Obsolete("Use System.Web.Security.Membership.DeleteUser")] + public override void delete() { DeleteEventArgs e = new DeleteEventArgs(); @@ -721,7 +721,7 @@ namespace umbraco.cms.businesslogic.member /// /// The id of the group which the member is being added to [MethodImpl(MethodImplOptions.Synchronized)] - [Obsolete("Use System.Web.Security.Roles.AddUserToRole")] + public void AddGroup(int GroupId) { AddGroupEventArgs e = new AddGroupEventArgs(); @@ -747,7 +747,7 @@ namespace umbraco.cms.businesslogic.member /// Removes the member from the MemberGroup specified /// /// The MemberGroup from which the Member is removed - [Obsolete("Use System.Web.Security.Roles.RemoveUserFromRole")] + public void RemoveGroup(int GroupId) { RemoveGroupEventArgs e = new RemoveGroupEventArgs();