From d821401ea2dae1d3db8105cf0f114ea4b9243450 Mon Sep 17 00:00:00 2001 From: neehouse Date: Fri, 6 Sep 2013 15:34:19 -0400 Subject: [PATCH 01/58] Removing file location restriction from PartialViewMacro to allow custom paths. --- src/Umbraco.Web/Macros/PartialViewMacroEngine.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs index e454a99f17..3e819a737d 100644 --- a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs +++ b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs @@ -104,11 +104,11 @@ namespace Umbraco.Web.Macros if (currentPage == null) throw new ArgumentNullException("currentPage"); if (macro.ScriptName.IsNullOrWhiteSpace()) throw new ArgumentException("The ScriptName property of the macro object cannot be null or empty"); - if (!macro.ScriptName.StartsWith(SystemDirectories.MvcViews + "/MacroPartials/") - && (!Regex.IsMatch(macro.ScriptName, "~/App_Plugins/.+?/Views/MacroPartials", RegexOptions.Compiled))) - { - throw new InvalidOperationException("Cannot render the Partial View Macro with file: " + macro.ScriptName + ". All Partial View Macros must exist in the " + SystemDirectories.MvcViews + "/MacroPartials/ folder"); - } + //if (!macro.ScriptName.StartsWith(SystemDirectories.MvcViews + "/MacroPartials/") + // && (!Regex.IsMatch(macro.ScriptName, "~/App_Plugins/.+?/Views/MacroPartials", RegexOptions.Compiled))) + //{ + // throw new InvalidOperationException("Cannot render the Partial View Macro with file: " + macro.ScriptName + ". All Partial View Macros must exist in the " + SystemDirectories.MvcViews + "/MacroPartials/ folder"); + //} var http = _getHttpContext(); var umbCtx = _getUmbracoContext(); From 998e2228815667c04436aa544ed784bdfa93f21f Mon Sep 17 00:00:00 2001 From: neehouse Date: Mon, 9 Sep 2013 14:00:08 -0400 Subject: [PATCH 02/58] Adding event to RenderMacro methods to allow for manipulation of the MacroModel. --- src/Umbraco.Web/umbraco.presentation/macro.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index d8914040ac..180d69a015 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -231,8 +231,22 @@ namespace umbraco return renderMacro(pageElements, pageId); } + public delegate void RenderEventHandler(MacroModel sender, RenderEventArgs e); + public new static event RenderEventHandler BeforeRender; + protected virtual void FireBeforeRender(RenderEventArgs e) + { + if (BeforeRender != null) + BeforeRender(Model, e); + } + + public Control renderMacro(Hashtable pageElements, int pageId) { + // Event to allow manipulation of Macro Model + var rea = new RenderEventArgs(); + FireBeforeRender(rea); + + var macroInfo = (Model.MacroType == MacroTypes.Script && Model.Name.IsNullOrWhiteSpace()) ? string.Format("Render Inline Macro, Cache: {0})", Model.CacheDuration) : string.Format("Render Macro: {0}, type: {1}, cache: {2})", Name, Model.MacroType, Model.CacheDuration); @@ -1952,4 +1966,6 @@ namespace umbraco #endregion } + public class RenderEventArgs : System.ComponentModel.CancelEventArgs { } + } \ No newline at end of file From c0214ac4ec75d1c8d6d0d8ce53a5523298ddfd87 Mon Sep 17 00:00:00 2001 From: neehouse Date: Tue, 10 Sep 2013 09:34:19 -0400 Subject: [PATCH 03/58] Modified the MacroRendering event as requested. Removed the unnecessary check for the file path from the Partial View Macro as it would not be hit anyhow since the macro engine is determined using the same rule. U4-2644 & U4-2643 --- src/Umbraco.Web/Macros/PartialViewMacroEngine.cs | 6 ------ src/Umbraco.Web/umbraco.presentation/macro.cs | 16 ++++++++-------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs index 3e819a737d..507b9fbb6e 100644 --- a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs +++ b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs @@ -104,12 +104,6 @@ namespace Umbraco.Web.Macros if (currentPage == null) throw new ArgumentNullException("currentPage"); if (macro.ScriptName.IsNullOrWhiteSpace()) throw new ArgumentException("The ScriptName property of the macro object cannot be null or empty"); - //if (!macro.ScriptName.StartsWith(SystemDirectories.MvcViews + "/MacroPartials/") - // && (!Regex.IsMatch(macro.ScriptName, "~/App_Plugins/.+?/Views/MacroPartials", RegexOptions.Compiled))) - //{ - // throw new InvalidOperationException("Cannot render the Partial View Macro with file: " + macro.ScriptName + ". All Partial View Macros must exist in the " + SystemDirectories.MvcViews + "/MacroPartials/ folder"); - //} - var http = _getHttpContext(); var umbCtx = _getUmbracoContext(); var routeVals = new RouteData(); diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 180d69a015..d2ad5fe292 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -231,20 +231,20 @@ namespace umbraco return renderMacro(pageElements, pageId); } - public delegate void RenderEventHandler(MacroModel sender, RenderEventArgs e); - public new static event RenderEventHandler BeforeRender; - protected virtual void FireBeforeRender(RenderEventArgs e) + public delegate void OnMacroRenderingEventHandler(macro sender, EventArgs e); + public static event OnMacroRenderingEventHandler OnMacroRendering; + protected void FireOnMacroRendering(EventArgs e) { - if (BeforeRender != null) - BeforeRender(Model, e); + if (OnMacroRendering != null) + OnMacroRendering(this, e); } public Control renderMacro(Hashtable pageElements, int pageId) { // Event to allow manipulation of Macro Model - var rea = new RenderEventArgs(); - FireBeforeRender(rea); + var rea = new EventArgs(); + FireOnMacroRendering(rea); var macroInfo = (Model.MacroType == MacroTypes.Script && Model.Name.IsNullOrWhiteSpace()) @@ -1966,6 +1966,6 @@ namespace umbraco #endregion } - public class RenderEventArgs : System.ComponentModel.CancelEventArgs { } + public class MacroRenderingEventArgs : System.EventArgs { } } \ No newline at end of file From 1781528390546652f36eac6a56213586c306ae69 Mon Sep 17 00:00:00 2001 From: neehouse Date: Tue, 10 Sep 2013 09:36:09 -0400 Subject: [PATCH 04/58] Removing Whitespace --- src/Umbraco.Web/umbraco.presentation/macro.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index d2ad5fe292..a3348e76a2 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -239,14 +239,12 @@ namespace umbraco OnMacroRendering(this, e); } - public Control renderMacro(Hashtable pageElements, int pageId) { // Event to allow manipulation of Macro Model var rea = new EventArgs(); FireOnMacroRendering(rea); - var macroInfo = (Model.MacroType == MacroTypes.Script && Model.Name.IsNullOrWhiteSpace()) ? string.Format("Render Inline Macro, Cache: {0})", Model.CacheDuration) : string.Format("Render Macro: {0}, type: {1}, cache: {2})", Name, Model.MacroType, Model.CacheDuration); From 4d726167f6043758a4c298c0ea0c24032034fc58 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Sep 2013 14:22:41 +0200 Subject: [PATCH 05/58] Core.XmlHelper - refactor --- src/Umbraco.Core/XmlHelper.cs | 82 +++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Core/XmlHelper.cs b/src/Umbraco.Core/XmlHelper.cs index c6249c8774..1d311cc7dc 100644 --- a/src/Umbraco.Core/XmlHelper.cs +++ b/src/Umbraco.Core/XmlHelper.cs @@ -50,7 +50,7 @@ namespace Umbraco.Core { try { - doc = new XPathDocument(new XmlTextReader(new StringReader(xml))); + doc = CreateXPathDocument(xml); return true; } catch (Exception) @@ -63,23 +63,68 @@ namespace Umbraco.Core /// /// Tries to create a new XPathDocument from a property value. /// - /// The alias of the property. /// The value of the property. /// The XPath document. /// A value indicating whether it has been possible to create the document. - public static bool TryCreateXPathDocumentFromPropertyValue(string alias, object value, out XPathDocument doc) + /// The value can be anything... Performance-wise, this is bad. + public static bool TryCreateXPathDocumentFromPropertyValue(object value, out XPathDocument doc) { - // In addition, DynamicNode strips dashes in elements or attributes - // names but really, this is ugly enough, and using dashes should be - // illegal in content type or property aliases anyway. + // DynamicNode.ConvertPropertyValueByDataType first cleans the value by calling + // XmlHelper.StripDashesInElementOrAttributeName - this is because the XML is + // to be returned as a DynamicXml and element names such as "value-item" are + // invalid and must be converted to "valueitem". But we don't have that sort of + // problem here - and we don't need to bother with dashes nor dots, etc. doc = null; var xml = value as string; - if (xml == null) return false; - xml = xml.Trim(); - if (xml.StartsWith("<") == false || xml.EndsWith(">") == false || xml.Contains('/') == false) return false; - if (UmbracoSettings.NotDynamicXmlDocumentElements.Any(x => x.InvariantEquals(alias))) return false; - return TryCreateXPathDocument(xml, out doc); + if (xml == null) return false; // no a string + if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml + if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise + if (TryCreateXPathDocument(xml, out doc) == false) return false; // string can't be parsed into xml + + var nav = doc.CreateNavigator(); + if (nav.MoveToFirstChild()) + { + var name = nav.LocalName; // must not match an excluded tag + if (UmbracoSettings.NotDynamicXmlDocumentElements.All(x => x.InvariantEquals(name) == false)) return true; + } + + doc = null; + return false; + } + + /// + /// Tries to create a new XElement from a property value. + /// + /// The value of the property. + /// The Xml element. + /// A value indicating whether it has been possible to create the element. + /// The value can be anything... Performance-wise, this is bad. + public static bool TryCreateXElementFromPropertyValue(object value, out XElement elt) + { + // see note above in TryCreateXPathDocumentFromPropertyValue... + + elt = null; + var xml = value as string; + if (xml == null) return false; // not a string + if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml + if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise + + try + { + elt = XElement.Parse(xml, LoadOptions.None); + } + catch + { + elt = null; + return false; // string can't be parsed into xml + } + + var name = elt.Name.LocalName; // must not match an excluded tag + if (UmbracoSettings.NotDynamicXmlDocumentElements.All(x => x.InvariantEquals(name) == false)) return true; + + elt = null; + return false; } /// @@ -137,8 +182,8 @@ namespace Umbraco.Core } } } - + // used by DynamicNode only, see note in TryCreateXPathDocumentFromPropertyValue public static string StripDashesInElementOrAttributeNames(string xml) { using (var outputms = new MemoryStream()) @@ -289,17 +334,10 @@ namespace Umbraco.Core /// public static bool CouldItBeXml(string xml) { - if (string.IsNullOrEmpty(xml) == false) - { - xml = xml.Trim(); + if (string.IsNullOrEmpty(xml)) return false; - if (xml.StartsWith("<") && xml.EndsWith(">") && xml.Contains("/")) - { - return true; - } - } - - return false; + xml = xml.Trim(); + return xml.StartsWith("<") && xml.EndsWith(">") && xml.Contains('/'); } /// From 6e0fa9f9458eefda5e97e81271f36ecbefc00d24 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Jun 2013 15:08:47 +0200 Subject: [PATCH 06/58] Core.Configuration - support missing notDynamicXmlDocumentElements --- src/Umbraco.Core/Configuration/UmbracoSettings.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs index 9292fd21e9..22b5e4e3b6 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs @@ -514,12 +514,10 @@ namespace Umbraco.Core.Configuration { try { - List items = new List(); - XmlNode root = GetKeyAsNode("/settings/scripting/razor/notDynamicXmlDocumentElements"); - foreach (XmlNode element in root.SelectNodes(".//element")) - { - items.Add(element.InnerText); - } + var items = new List(); + var root = GetKeyAsNode("/settings/scripting/razor/notDynamicXmlDocumentElements"); + if (root != null) + items.AddRange(root.SelectNodes(".//element").Cast().Select(n => n.InnerText)); return items; } catch From ddfd9eeb185f3837068d0e77dc62bb5dd8b3f3c5 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 14 Jun 2013 00:30:02 +0200 Subject: [PATCH 07/58] Core.UriExtensions - refactor + issue with IsClientSideRequest --- src/Umbraco.Core/UriExtensions.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 6ecb8d67e8..9de8cf4867 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Linq; -using System.Text; using Umbraco.Core.Configuration; using Umbraco.Core.IO; @@ -57,6 +56,7 @@ namespace Umbraco.Core /// internal static bool IsClientSideRequest(this Uri url) { + // fixme - but really, is this OK? we should accept either no url, or .aspx, and everything else is out var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif", ".html", ".svg" }; return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x)); } @@ -70,7 +70,7 @@ namespace Umbraco.Core /// Everything else remains unchanged, except for the fragment which is removed. public static Uri Rewrite(this Uri uri, string path) { - if (!path.StartsWith("/")) + if (path.StartsWith("/") == false) throw new ArgumentException("Path must start with a slash.", "path"); return uri.IsAbsoluteUri @@ -88,9 +88,9 @@ namespace Umbraco.Core /// Everything else remains unchanged, except for the fragment which is removed. public static Uri Rewrite(this Uri uri, string path, string query) { - if (!path.StartsWith("/")) + if (path.StartsWith("/") == false) throw new ArgumentException("Path must start with a slash.", "path"); - if (query.Length > 0 && !query.StartsWith("?")) + if (query.Length > 0 && query.StartsWith("?") == false) throw new ArgumentException("Query must start with a question mark.", "query"); if (query == "?") query = ""; @@ -153,15 +153,14 @@ namespace Umbraco.Core var path = uri.GetSafeAbsolutePath(); if (uri.IsAbsoluteUri) { - if (path != "/" && !path.EndsWith("/")) + if (path != "/" && path.EndsWith("/") == false) uri = new Uri(uri.GetLeftPart(UriPartial.Authority) + path + "/" + uri.Query); return uri; } - else - { - if (path != "/" && !path.EndsWith("/")) - uri = new Uri(path + "/" + uri.Query, UriKind.Relative); - } + + if (path != "/" && path.EndsWith("/") == false) + uri = new Uri(path + "/" + uri.Query, UriKind.Relative); + return uri; } From 447b3227a97bb2c62c8b5777ca76631ac8845e4e Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Jun 2013 01:51:02 +0200 Subject: [PATCH 08/58] Web.Routing - remove duplicate code --- src/Umbraco.Web/Routing/DefaultUrlProvider.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs index a2285ddc74..bc5752ed67 100644 --- a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs @@ -110,13 +110,6 @@ namespace Umbraco.Web.Routing : UrlProviderMode.Auto; } - if (mode == UrlProviderMode.AutoLegacy) - { - mode = Core.Configuration.UmbracoSettings.UseDomainPrefixes - ? UrlProviderMode.Absolute - : UrlProviderMode.Auto; - } - if (domainUri == null) // no domain was found { if (current == null) From 9fa5821f078bf0ff7646db6a96330c411398f61e Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Jun 2013 15:04:47 +0200 Subject: [PATCH 09/58] Comments - Web.Standalone --- src/Umbraco.Web/Standalone/StandaloneBootManager.cs | 9 +++++---- src/Umbraco.Web/Standalone/StandaloneHttpContext.cs | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web/Standalone/StandaloneBootManager.cs b/src/Umbraco.Web/Standalone/StandaloneBootManager.cs index cf2e8f7c11..8e69797a4d 100644 --- a/src/Umbraco.Web/Standalone/StandaloneBootManager.cs +++ b/src/Umbraco.Web/Standalone/StandaloneBootManager.cs @@ -15,8 +15,9 @@ namespace Umbraco.Web.Standalone /// internal class StandaloneBootManager : CoreBootManager { - // fixme - could we inherit from WebBootManager? - // fixme - highly experimental, probably not complete! + // TODO + // this is highly experimental and probably not complete - not for production usage! + // also, could we inherit from WebBootManager? private readonly IEnumerable _handlersToAdd; private readonly IEnumerable _handlersToRemove; @@ -35,7 +36,7 @@ namespace Umbraco.Web.Standalone // the DataTypesResolver otherwise they won't be loaded into the AppDomain. var interfacesAssemblyName = typeof(IDataType).Assembly.FullName; - // fixme - there's also that one... but we don't use it in standalone? + // TODO there's also that one... but we don't use it in standalone? //using umbraco.editorControls; //var editorControlsAssemblyName = typeof(uploadField).Assembly.FullName; } @@ -70,7 +71,7 @@ namespace Umbraco.Web.Standalone typeof (ContentFinderByNotFoundHandlers) ); - // fixme - what else? + // TODO what else? } // can't create context before resolution is frozen! diff --git a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs index 55339e97b6..ac34e405e5 100644 --- a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs +++ b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs @@ -22,7 +22,6 @@ namespace Umbraco.Web.Standalone public StandaloneHttpContext() { - //create a custom response with a custom writer. _response = new HttpResponseWrapper(new HttpResponse(_writer)); } @@ -35,7 +34,7 @@ namespace Umbraco.Web.Standalone } - // fixme - what shall we implement here? + // what else should we implement here? public override IDictionary Items { From 433e1417612e2ce1419552aaa0650164c2984082 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 11 Jun 2013 15:07:53 +0200 Subject: [PATCH 10/58] Comments - misc --- src/Umbraco.Core/ApplicationContext.cs | 2 +- .../PublishedCache/XmlPublishedCache/RoutesCache.cs | 3 +-- src/Umbraco.Web/Routing/LegacyRequestInitializer.cs | 2 +- src/Umbraco.Web/UriUtility.cs | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs index 815e69acb4..78ed2c755a 100644 --- a/src/Umbraco.Core/ApplicationContext.cs +++ b/src/Umbraco.Core/ApplicationContext.cs @@ -116,7 +116,7 @@ namespace Umbraco.Core // public bool IsConfigured { - // fixme - let's do this for the time being + // fixme - we should not do this - ok for now get { return Configured; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/RoutesCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/RoutesCache.cs index 8d1d88be2e..1775d37fe0 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/RoutesCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/RoutesCache.cs @@ -45,11 +45,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // document - whenever a document is updated in, or removed from, the XML cache // we must clear the cache - at the moment, we clear the entire cache - // TODO could we do partial updates instead of clearing the whole cache? global::umbraco.content.AfterUpdateDocumentCache += (sender, e) => Clear(); global::umbraco.content.AfterClearDocumentCache += (sender, e) => Clear(); - // FIXME + // fixme - refactor when content events are refactored // the content class needs to be refactored - at the moment // content.XmlContentInternal setter does not trigger any event // content.UpdateDocumentCache(List Documents) does not trigger any event diff --git a/src/Umbraco.Web/Routing/LegacyRequestInitializer.cs b/src/Umbraco.Web/Routing/LegacyRequestInitializer.cs index b6373d410b..9baec728f1 100644 --- a/src/Umbraco.Web/Routing/LegacyRequestInitializer.cs +++ b/src/Umbraco.Web/Routing/LegacyRequestInitializer.cs @@ -27,7 +27,7 @@ namespace Umbraco.Web.Routing // legacy - umbOriginalUrl used by presentation/umbraco/urlRewriter/UrlRewriterFormWriter which handles
Date: Fri, 14 Jun 2013 00:31:53 +0200 Subject: [PATCH 11/58] Comments - UmbracoModule --- src/Umbraco.Web/UmbracoModule.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 132741e7ac..a1482c08e1 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -43,6 +43,7 @@ namespace Umbraco.Web //see: http://issues.umbraco.org/issue/U4-2059 if (ApplicationContext.Current.OriginalRequestUrl.IsNullOrWhiteSpace()) { + // the keepalive service will use that url ApplicationContext.Current.OriginalRequestUrl = string.Format("{0}:{1}{2}", httpContext.Request.ServerVariables["SERVER_NAME"], httpContext.Request.ServerVariables["SERVER_PORT"], IOHelper.ResolveUrl(SystemDirectories.Umbraco)); } From 85ab96f71a07b623af59c4d6bb9560478fd73a5d Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Sep 2013 17:14:06 +0200 Subject: [PATCH 12/58] Core.Attempt - refactor and cleanup --- src/Umbraco.Core/Attempt.cs | 106 +++++++------- src/Umbraco.Core/Attempt{T}.cs | 129 ++++++++++++++++++ .../Dynamics/DynamicInstanceHelper.cs | 14 +- src/Umbraco.Core/Dynamics/DynamicXml.cs | 14 +- src/Umbraco.Core/ObjectExtensions.cs | 38 +++--- .../Persistence/Mappers/MappingResolver.cs | 8 +- .../Repositories/RepositoryBase.cs | 4 +- src/Umbraco.Core/PluginManager.cs | 14 +- src/Umbraco.Core/Profiling/WebProfiler.cs | 6 +- .../TinyMcePropertyEditorValueConverter.cs | 2 +- src/Umbraco.Core/PublishedContentHelper.cs | 18 +-- .../Publishing/PublishingStrategy.cs | 28 ++-- src/Umbraco.Core/Services/ContentService.cs | 8 +- src/Umbraco.Core/TypeHelper.cs | 8 +- src/Umbraco.Core/Umbraco.Core.csproj | 3 +- .../Models/DynamicPublishedContent.cs | 24 ++-- .../Models/DynamicPublishedContentList.cs | 2 +- src/Umbraco.Web/Mvc/SurfaceController.cs | 6 +- ...roRenderingPropertyEditorValueConverter.cs | 2 +- src/Umbraco.Web/UmbracoModule.cs | 2 +- .../WebApi/UmbracoApiController.cs | 6 +- .../RazorDynamicNode/DynamicNode.cs | 4 +- src/umbraco.cms/businesslogic/web/Document.cs | 9 +- 23 files changed, 284 insertions(+), 171 deletions(-) create mode 100644 src/Umbraco.Core/Attempt{T}.cs diff --git a/src/Umbraco.Core/Attempt.cs b/src/Umbraco.Core/Attempt.cs index c184c5670a..ed7c978b52 100644 --- a/src/Umbraco.Core/Attempt.cs +++ b/src/Umbraco.Core/Attempt.cs @@ -2,65 +2,55 @@ using System; namespace Umbraco.Core { - /// - /// Represents the result of an operation attempt - /// - /// - /// - [Serializable] - public struct Attempt - { - private readonly bool _success; - private readonly T _result; - private readonly Exception _error; + /// + /// Provides ways to create attempts. + /// + public static class Attempt + { + /// + /// Creates a successful attempt with a result. + /// + /// The type of the attempted operation result. + /// The result of the attempt. + /// The successful attempt. + public static Attempt Succ(T result) + { + return Attempt.Succ(result); + } - /// - /// Gets a value indicating whether this represents a successful operation. - /// - /// - public bool Success - { - get { return _success; } - } + /// + /// Creates a failed attempt with a result. + /// + /// The type of the attempted operation result. + /// The result of the attempt. + /// The failed attempt. + public static Attempt Fail(T result) + { + return Attempt.Fail(result); + } - /// - /// Gets the error associated with an unsuccessful attempt. - /// - /// The error. - public Exception Error { get { return _error; } } + /// + /// Creates a failed attempt with a result and an exception. + /// + /// The type of the attempted operation result. + /// The result of the attempt. + /// The exception causing the failure of the attempt. + /// The failed attempt. + public static Attempt Fail(T result, Exception exception) + { + return Attempt.Fail(result, exception); + } - /// - /// Gets the parse result. - /// - /// - public T Result - { - get { return _result; } - } - - /// - /// Represents an unsuccessful parse operation - /// - public static readonly Attempt False = new Attempt(false, default(T)); - - /// - /// Initializes a new instance of the struct. - /// - /// If set to true this tuple represents a successful parse result. - /// The parse result. - /// - public Attempt(bool success, T result) - { - _success = success; - _result = result; - _error = null; - } - - public Attempt(Exception error) - { - _success = false; - _result = default(T); - _error = error; - } - } + /// + /// Creates a successful or a failed attempt, with a result. + /// + /// The type of the attempted operation result. + /// A value indicating whether the attempt is successful. + /// The result of the attempt. + /// The attempt. + public static Attempt If(bool success, T result) + { + return Attempt.If(success, result); + } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Attempt{T}.cs b/src/Umbraco.Core/Attempt{T}.cs new file mode 100644 index 0000000000..a5dce955c7 --- /dev/null +++ b/src/Umbraco.Core/Attempt{T}.cs @@ -0,0 +1,129 @@ +using System; +using Umbraco.Core.Dynamics; + +namespace Umbraco.Core +{ + /// + /// Represents the result of an operation attempt. + /// + /// The type of the attempted operation result. + [Serializable] + public struct Attempt + { + private readonly bool _success; + private readonly T _result; + private readonly Exception _exception; + + /// + /// Gets a value indicating whether this was successful. + /// + public bool Success + { + get { return _success; } + } + + /// + /// Gets the exception associated with an unsuccessful attempt. + /// + public Exception Exception { get { return _exception; } } + + /// + /// Gets the attempt result. + /// + public T Result + { + get { return _result; } + } + + // optimize, use a singleton failed attempt + private static readonly Attempt Failed = new Attempt(false, default(T), null); + + // private - use Succ() or Fail() methods to create attempts + private Attempt(bool success, T result, Exception exception) + { + _success = success; + _result = result; + _exception = exception; + } + + /// + /// Creates a successful attempt. + /// + /// The successful attempt. + public static Attempt Succ() + { + return new Attempt(true, default(T), null); + } + + /// + /// Creates a successful attempt with a result. + /// + /// The result of the attempt. + /// The successful attempt. + public static Attempt Succ(T result) + { + return new Attempt(true, result, null); + } + + /// + /// Creates a failed attempt. + /// + /// The failed attempt. + public static Attempt Fail() + { + return Failed; + } + + /// + /// Creates a failed attempt with an exception. + /// + /// The exception causing the failure of the attempt. + /// The failed attempt. + public static Attempt Fail(Exception exception) + { + return new Attempt(false, default(T), exception); + } + + /// + /// Creates a failed attempt with a result. + /// + /// The result of the attempt. + /// The failed attempt. + public static Attempt Fail(T result) + { + return new Attempt(false, result, null); + } + + /// + /// Creates a failed attempt with a result and an exception. + /// + /// The result of the attempt. + /// The exception causing the failure of the attempt. + /// The failed attempt. + public static Attempt Fail(T result, Exception exception) + { + return new Attempt(false, result, exception); + } + + /// + /// Creates a successful or a failed attempt. + /// + /// A value indicating whether the attempt is successful. + /// The attempt. + public static Attempt If(bool success) + { + return success ? new Attempt(true, default(T), null) : Failed; + } + + /// + /// Creates a successful or a failed attempt, with a result. + /// + /// A value indicating whether the attempt is successful. + /// The result of the attempt. + /// The attempt. + public static Attempt If(bool success, T result) + { + return new Attempt(success, result, null); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs index a7bb20ef5b..b0e5981bff 100644 --- a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs +++ b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs @@ -82,7 +82,7 @@ namespace Umbraco.Core.Dynamics null, thisObject, args); - return new Attempt(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty)); + return Attempt.Succ(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty)); } catch (MissingMethodException) { @@ -97,7 +97,7 @@ namespace Umbraco.Core.Dynamics null, thisObject, args); - return new Attempt(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod)); + return Attempt.Succ(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod)); } catch (MissingMethodException) { @@ -106,13 +106,13 @@ namespace Umbraco.Core.Dynamics try { result = FindAndExecuteExtensionMethod(thisObject, args, binder.Name, findExtensionMethodsOnTypes); - return new Attempt(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod)); + return Attempt.Succ(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod)); } catch (TargetInvocationException ext) { //don't log here, we return this exception because the caller may need to do something specific when //this exception occurs. - return new Attempt(ext); + return Attempt.Fail(ext); } catch (Exception ex) { @@ -124,16 +124,16 @@ namespace Umbraco.Core.Dynamics sb.Append(t + ","); } LogHelper.Error(sb.ToString(), ex); - return new Attempt(ex); + return Attempt.Fail(ex); } } - return Attempt.False; + return Attempt.Fail(); } } catch (Exception ex) { LogHelper.Error("An unhandled exception occurred in method TryInvokeMember", ex); - return new Attempt(ex); + return Attempt.Fail(ex); } } diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs index 0e0d14d9c9..0e02e44db9 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXml.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXml.cs @@ -201,7 +201,7 @@ namespace Umbraco.Core.Dynamics //this is the result of an extension method execution gone wrong so we return dynamic null if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod - && attempt.Error != null && attempt.Error is TargetInvocationException) + && attempt.Exception != null && attempt.Exception is TargetInvocationException) { result = new DynamicNull(); return true; @@ -261,7 +261,7 @@ namespace Umbraco.Core.Dynamics var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray(); if (attributes.Any()) { - return new Attempt>(true, attributes); + return Attempt>.Succ(attributes); } if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) @@ -271,12 +271,12 @@ namespace Umbraco.Core.Dynamics if (childElements.Any()) { //we've found a match by the first child of an element called 'root' (strange, but sure) - return new Attempt>(true, childElements); + return Attempt>.Succ(childElements); } } //no deal - return Attempt>.False; + return Attempt>.Fail(); } /// @@ -293,7 +293,7 @@ namespace Umbraco.Core.Dynamics //Check if we've got any matches, if so then return true if (elements.Any()) { - return new Attempt>(true, elements); + return Attempt>.Succ(elements); } if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) @@ -303,12 +303,12 @@ namespace Umbraco.Core.Dynamics if (childElements.Any()) { //we've found a match by the first child of an element called 'root' (strange, but sure) - return new Attempt>(true, childElements); + return Attempt>.Succ(childElements); } } //no deal - return Attempt>.False; + return Attempt>.Fail(); } private bool HandleIEnumerableXElement(IEnumerable elements, out object result) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 434f71cb18..7726af50ff 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -58,14 +58,14 @@ namespace Umbraco.Core try { var converted = (T) input; - return new Attempt(true, converted); + return Attempt.Succ(converted); } catch (Exception e) { - return new Attempt(e); + return Attempt.Fail(e); } } - return !result.Success ? Attempt.False : new Attempt(true, (T)result.Result); + return !result.Success ? Attempt.Fail() : Attempt.Succ((T)result.Result); } /// @@ -77,11 +77,11 @@ namespace Umbraco.Core /// public static Attempt TryConvertTo(this object input, Type destinationType) { - if (input == null) return Attempt.False; + if (input == null) return Attempt.Fail(); - if (destinationType == typeof(object)) return new Attempt(true, input); + if (destinationType == typeof(object)) return Attempt.Succ(input); - if (input.GetType() == destinationType) return new Attempt(true, input); + if (input.GetType() == destinationType) return Attempt.Succ(input); if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>)) { @@ -94,11 +94,11 @@ namespace Umbraco.Core try { var casted = Convert.ChangeType(input, destinationType); - return new Attempt(true, casted); + return Attempt.Succ(casted); } catch (Exception e) { - return new Attempt(e); + return Attempt.Fail(e); } } } @@ -109,11 +109,11 @@ namespace Umbraco.Core try { var converted = inputConverter.ConvertTo(input, destinationType); - return new Attempt(true, converted); + return Attempt.Succ(converted); } catch (Exception e) { - return new Attempt(e); + return Attempt.Fail(e); } } @@ -125,11 +125,11 @@ namespace Umbraco.Core try { var converted = boolConverter.ConvertFrom(input); - return new Attempt(true, converted); + return Attempt.Succ(converted); } catch (Exception e) { - return new Attempt(e); + return Attempt.Fail(e); } } } @@ -140,11 +140,11 @@ namespace Umbraco.Core try { var converted = outputConverter.ConvertFrom(input); - return new Attempt(true, converted); + return Attempt.Succ(converted); } catch (Exception e) { - return new Attempt(e); + return Attempt.Fail(e); } } @@ -154,15 +154,15 @@ namespace Umbraco.Core try { var casted = Convert.ChangeType(input, destinationType); - return new Attempt(true, casted); + return Attempt.Succ(casted); } catch (Exception e) { - return new Attempt(e); + return Attempt.Fail(e); } } - return Attempt.False; + return Attempt.Fail(); } internal static void CheckThrowObjectDisposed(this IDisposable disposable, bool isDisposed, string objectname) @@ -351,11 +351,11 @@ namespace Umbraco.Core try { var output = value.ToXmlString(type); - return new Attempt(true, output); + return Attempt.Succ(output); } catch (NotSupportedException ex) { - return new Attempt(ex); + return Attempt.Fail(ex); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs b/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs index cb5d7c95a1..8c576f1e63 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs @@ -67,19 +67,19 @@ namespace Umbraco.Core.Persistence.Mappers if (mapper == null) { - return Attempt.False; + return Attempt.Fail(); } try { var instance = Activator.CreateInstance(mapper) as BaseMapper; return instance != null - ? new Attempt(true, instance) - : Attempt.False; + ? Attempt.Succ(instance) + : Attempt.Fail(); } catch (Exception ex) { LogHelper.Error(typeof(MappingResolver), "Could not instantiate mapper of type " + mapper, ex); - return new Attempt(ex); + return Attempt.Fail(ex); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 3967aef5e6..b9f20cd706 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -117,9 +117,9 @@ namespace Umbraco.Core.Persistence.Repositories var rEntity = _cache.GetById(typeof(TEntity), key); if (rEntity != null) { - return new Attempt(true, (TEntity) rEntity); + return Attempt.Succ((TEntity) rEntity); } - return Attempt.False; + return Attempt.Fail(); } protected abstract IEnumerable PerformGetAll(params TId[] ids); diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index f798c2a454..1db052396a 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -242,7 +242,7 @@ namespace Umbraco.Core { var filePath = GetPluginListFilePath(); if (!File.Exists(filePath)) - return Attempt>.False; + return Attempt>.Fail(); try { @@ -262,7 +262,7 @@ namespace Umbraco.Core if (xml.Root == null) - return Attempt>.False; + return Attempt>.Fail(); var typeElement = xml.Root.Elements() .SingleOrDefault(x => @@ -272,18 +272,16 @@ namespace Umbraco.Core //return false but specify this exception type so we can detect it if (typeElement == null) - return new Attempt>(new CachedPluginNotFoundInFile()); + return Attempt>.Fail(new CachedPluginNotFoundInFile()); //return success - return new Attempt>( - true, - typeElement.Elements("add") + return Attempt.Succ(typeElement.Elements("add") .Select(x => (string)x.Attribute("type"))); } catch (Exception ex) { //if the file is corrupted, etc... return false - return new Attempt>(ex); + return Attempt>.Fail(ex); } } @@ -621,7 +619,7 @@ namespace Umbraco.Core //here we need to identify if the CachedPluginNotFoundInFile was the exception, if it was then we need to re-scan //in some cases the plugin will not have been scanned for on application startup, but the assemblies haven't changed //so in this instance there will never be a result. - if (fileCacheResult.Error != null && fileCacheResult.Error is CachedPluginNotFoundInFile) + if (fileCacheResult.Exception != null && fileCacheResult.Exception is CachedPluginNotFoundInFile) { //we don't have a cache for this so proceed to look them up by scanning LoadViaScanningAndUpdateCacheFile(typeList, resolutionType, finder); diff --git a/src/Umbraco.Core/Profiling/WebProfiler.cs b/src/Umbraco.Core/Profiling/WebProfiler.cs index 3a1974279e..6dae4cde0c 100644 --- a/src/Umbraco.Core/Profiling/WebProfiler.cs +++ b/src/Umbraco.Core/Profiling/WebProfiler.cs @@ -143,16 +143,16 @@ namespace Umbraco.Core.Profiling private Attempt TryGetRequest(object sender) { var app = sender as HttpApplication; - if (app == null) return Attempt.False; + if (app == null) return Attempt.Fail(); try { var req = app.Request; - return new Attempt(true, new HttpRequestWrapper(req)); + return Attempt.Succ(new HttpRequestWrapper(req)); } catch (HttpException ex) { - return new Attempt(ex); + return Attempt.Fail(ex); } } } diff --git a/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs b/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs index fec80ddc85..e6acbf36e0 100644 --- a/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.PropertyEditors /// public virtual Attempt ConvertPropertyValue(object value) { - return new Attempt(true, new HtmlString(value.ToString())); + return Attempt.Succ(new HtmlString(value.ToString())); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/PublishedContentHelper.cs b/src/Umbraco.Core/PublishedContentHelper.cs index 86513ede02..db8d2dbbe4 100644 --- a/src/Umbraco.Core/PublishedContentHelper.cs +++ b/src/Umbraco.Core/PublishedContentHelper.cs @@ -93,7 +93,7 @@ namespace Umbraco.Core /// internal static Attempt ConvertPropertyValue(object currentValue, Guid dataType, string docTypeAlias, string propertyTypeAlias) { - if (currentValue == null) return Attempt.False; + if (currentValue == null) return Attempt.Fail(); //First lets check all registered converters for this data type. var converters = PropertyEditorValueConvertersResolver.Current.Converters @@ -105,7 +105,7 @@ namespace Umbraco.Core .Select(p => p.ConvertPropertyValue(currentValue)) .Where(converted => converted.Success)) { - return new Attempt(true, converted.Result); + return Attempt.Succ(converted.Result); } //if none of the converters worked, then we'll process this from what we know @@ -118,17 +118,17 @@ namespace Umbraco.Core decimal dResult; if (decimal.TryParse(sResult, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.CurrentCulture, out dResult)) { - return new Attempt(true, dResult); + return Attempt.Succ(dResult); } } //process string booleans as booleans if (sResult.InvariantEquals("true")) { - return new Attempt(true, true); + return Attempt.Succ(true); } if (sResult.InvariantEquals("false")) { - return new Attempt(true, false); + return Attempt.Succ(false); } //a really rough check to see if this may be valid xml @@ -147,16 +147,16 @@ namespace Umbraco.Core if (!UmbracoSettings.NotDynamicXmlDocumentElements.Any( tag => string.Equals(tag, documentElement, StringComparison.CurrentCultureIgnoreCase))) { - return new Attempt(true, new DynamicXml(e)); + return Attempt.Succ(new DynamicXml(e)); } - return Attempt.False; + return Attempt.Fail(); } catch (Exception) { - return Attempt.False; + return Attempt.Fail(); } } - return Attempt.False; + return Attempt.Fail(); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Publishing/PublishingStrategy.cs b/src/Umbraco.Core/Publishing/PublishingStrategy.cs index 5f874a00b0..d115bb1a10 100644 --- a/src/Umbraco.Core/Publishing/PublishingStrategy.cs +++ b/src/Umbraco.Core/Publishing/PublishingStrategy.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Publishing { LogHelper.Info( string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", content.Name, content.Id)); - return new Attempt(false, new PublishStatus(content, PublishStatusType.FailedCancelledByEvent)); + return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent)); } @@ -35,7 +35,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' has expired and could not be published.", content.Name, content.Id)); - return new Attempt(false, new PublishStatus(content, PublishStatusType.FailedHasExpired)); + return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired)); } //Check if the Content is Awaiting Release to verify that it can in fact be published @@ -44,7 +44,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.", content.Name, content.Id)); - return new Attempt(false, new PublishStatus(content, PublishStatusType.FailedAwaitingRelease)); + return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease)); } //Check if the Content is Trashed to verify that it can in fact be published @@ -53,7 +53,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.", content.Name, content.Id)); - return new Attempt(false, new PublishStatus(content, PublishStatusType.FailedIsTrashed)); + return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed)); } content.ChangePublishedState(PublishedState.Published); @@ -62,7 +62,7 @@ namespace Umbraco.Core.Publishing string.Format("Content '{0}' with Id '{1}' has been published.", content.Name, content.Id)); - return new Attempt(true, new PublishStatus(content)); + return Attempt.Succ(new PublishStatus(content)); } /// @@ -125,7 +125,7 @@ namespace Umbraco.Core.Publishing //We're going to populate the statuses with all content that is already published because below we are only going to iterate over // content that is not published. We'll set the status to "AlreadyPublished" statuses.AddRange(fetchedContent.Where(x => x.Published) - .Select(x => new Attempt(true, new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished)))); + .Select(x => Attempt.Succ(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished)))); int? firstLevel = null; @@ -169,7 +169,7 @@ namespace Umbraco.Core.Publishing //the publishing has been cancelled. LogHelper.Info( string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id)); - statuses.Add(new Attempt(false, new PublishStatus(item, PublishStatusType.FailedCancelledByEvent))); + statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent))); //Does this document apply to our rule to cancel it's children being published? CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments); @@ -183,7 +183,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.", item.Name, item.Id)); - statuses.Add(new Attempt(false, new PublishStatus(item, PublishStatusType.FailedContentInvalid))); + statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid))); //Does this document apply to our rule to cancel it's children being published? CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments); @@ -197,7 +197,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' has expired and could not be published.", item.Name, item.Id)); - statuses.Add(new Attempt(false, new PublishStatus(item, PublishStatusType.FailedHasExpired))); + statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired))); //Does this document apply to our rule to cancel it's children being published? CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments); @@ -211,7 +211,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.", item.Name, item.Id)); - statuses.Add(new Attempt(false, new PublishStatus(item, PublishStatusType.FailedAwaitingRelease))); + statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease))); //Does this document apply to our rule to cancel it's children being published? CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments); @@ -225,7 +225,7 @@ namespace Umbraco.Core.Publishing LogHelper.Info( string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.", item.Name, item.Id)); - statuses.Add(new Attempt(false, new PublishStatus(item, PublishStatusType.FailedIsTrashed))); + statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed))); //Does this document apply to our rule to cancel it's children being published? CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments); @@ -239,7 +239,7 @@ namespace Umbraco.Core.Publishing string.Format("Content '{0}' with Id '{1}' has been published.", item.Name, item.Id)); - statuses.Add(new Attempt(true, new PublishStatus(item))); + statuses.Add(Attempt.Succ(new PublishStatus(item))); } } @@ -349,7 +349,7 @@ namespace Umbraco.Core.Publishing { LogHelper.Info( string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id)); - result.Add(new Attempt(false, new PublishStatus(item, PublishStatusType.FailedCancelledByEvent))); + result.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent))); continue; } @@ -370,7 +370,7 @@ namespace Umbraco.Core.Publishing string.Format("Content '{0}' with Id '{1}' has been unpublished.", item.Name, item.Id)); - result.Add(new Attempt(true, new PublishStatus(item))); + result.Add(Attempt.Succ(new PublishStatus(item))); } return result; diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index d4bf0b546d..76ee81f369 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1452,7 +1452,7 @@ namespace Umbraco.Core.Services string.Format( "Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.", content.Name, content.Id)); - result.Add(new Attempt(false, new PublishStatus(content, PublishStatusType.FailedPathNotPublished))); + result.Add(Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedPathNotPublished))); return result; } @@ -1463,7 +1463,7 @@ namespace Umbraco.Core.Services string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.", content.Name, content.Id)); result.Add( - new Attempt(false, + Attempt.Fail( new PublishStatus(content, PublishStatusType.FailedContentInvalid) { InvalidProperties = ((ContentBase) content).LastInvalidProperties @@ -1569,7 +1569,7 @@ namespace Umbraco.Core.Services { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) { - return new Attempt(false, new PublishStatus(content, PublishStatusType.FailedCancelledByEvent)); + return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent)); } } @@ -1639,7 +1639,7 @@ namespace Umbraco.Core.Services Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id); - return new Attempt(publishStatus.StatusType == PublishStatusType.Success, publishStatus); + return Attempt.If(publishStatus.StatusType == PublishStatusType.Success, publishStatus); } } diff --git a/src/Umbraco.Core/TypeHelper.cs b/src/Umbraco.Core/TypeHelper.cs index 26dd2a8402..71e558e55c 100644 --- a/src/Umbraco.Core/TypeHelper.cs +++ b/src/Umbraco.Core/TypeHelper.cs @@ -95,11 +95,11 @@ namespace Umbraco.Core { if (types.Length == 0) { - return Attempt.False; + return Attempt.Fail(); } if (types.Length == 1) { - return new Attempt(true, types[0]); + return Attempt.Succ(types[0]); } foreach (var curr in types) @@ -112,11 +112,11 @@ namespace Umbraco.Core //if this type is the base for all others if (isBase) { - return new Attempt(true, curr); + return Attempt.Succ(curr); } } - return Attempt.False; + return Attempt.Fail(); } /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 43b8891c92..2cc6a8fbd4 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -105,7 +105,7 @@ - + @@ -137,6 +137,7 @@ + diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index 3ff0732f99..57f5981385 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -131,7 +131,7 @@ namespace Umbraco.Web.Models //this is the result of an extension method execution gone wrong so we return dynamic null if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod - && attempt.Error != null && attempt.Error is TargetInvocationException) + && attempt.Exception != null && attempt.Exception is TargetInvocationException) { result = new DynamicNull(); return true; @@ -150,7 +150,7 @@ namespace Umbraco.Web.Models { if (binder.Name.InvariantEquals("ChildrenAsList") || binder.Name.InvariantEquals("Children")) { - return new Attempt(true, Children); + return Attempt.Succ(Children); } if (binder.Name.InvariantEquals("parentId")) @@ -160,9 +160,9 @@ namespace Umbraco.Web.Models { throw new InvalidOperationException(string.Format("The node {0} does not have a parent", Id)); } - return new Attempt(true, parent.Id); + return Attempt.Succ(parent.Id); } - return Attempt.False; + return Attempt.Fail(); } /// @@ -182,10 +182,10 @@ namespace Umbraco.Web.Models .ToArray(); if (filteredTypeChildren.Any()) { - return new Attempt(true, + return Attempt.Succ( new DynamicPublishedContentList(filteredTypeChildren.Select(x => new DynamicPublishedContent(x)))); } - return Attempt.False; + return Attempt.Fail(); } /// @@ -201,9 +201,7 @@ namespace Umbraco.Web.Models ? reflectedProperty.Value : null; - return result == null - ? Attempt.False - : new Attempt(true, result); + return Attempt.If(result != null, result); } /// @@ -225,7 +223,7 @@ namespace Umbraco.Web.Models if (userProperty == null) { - return Attempt.False; + return Attempt.Fail(); } var result = userProperty.Value; @@ -249,7 +247,7 @@ namespace Umbraco.Web.Models result = converted.Result; } - return new Attempt(true, result); + return Attempt.Succ(result); } @@ -384,7 +382,7 @@ namespace Umbraco.Web.Models { try { - return new Attempt(true, + return Attempt.Succ( content.GetType().InvokeMember(memberAlias, System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | @@ -395,7 +393,7 @@ namespace Umbraco.Web.Models } catch (MissingMethodException ex) { - return new Attempt(ex); + return Attempt.Fail(ex); } }; diff --git a/src/Umbraco.Web/Models/DynamicPublishedContentList.cs b/src/Umbraco.Web/Models/DynamicPublishedContentList.cs index 3b323b004a..d937a31bbe 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContentList.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContentList.cs @@ -273,7 +273,7 @@ namespace Umbraco.Web.Models //this is the result of an extension method execution gone wrong so we return dynamic null if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod - && attempt.Error != null && attempt.Error is TargetInvocationException) + && attempt.Exception != null && attempt.Exception is TargetInvocationException) { result = new DynamicNull(); return true; diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs index 23caa16619..0011718b3c 100644 --- a/src/Umbraco.Web/Mvc/SurfaceController.cs +++ b/src/Umbraco.Web/Mvc/SurfaceController.cs @@ -81,7 +81,7 @@ namespace Umbraco.Web.Mvc var routeDefAttempt = TryGetRouteDefinitionFromAncestorViewContexts(); if (!routeDefAttempt.Success) { - throw routeDefAttempt.Error; + throw routeDefAttempt.Exception; } var routeDef = routeDefAttempt.Result; @@ -105,7 +105,7 @@ namespace Umbraco.Web.Mvc var currentRouteData = currentContext.RouteData; if (currentRouteData.DataTokens.ContainsKey("umbraco-route-def")) { - return new Attempt(true, (RouteDefinition) currentRouteData.DataTokens["umbraco-route-def"]); + return Attempt.Succ((RouteDefinition) currentRouteData.DataTokens["umbraco-route-def"]); } if (currentContext.IsChildAction) { @@ -118,7 +118,7 @@ namespace Umbraco.Web.Mvc currentContext = null; } } - return new Attempt( + return Attempt.Fail( new InvalidOperationException("Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request")); } diff --git a/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs b/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs index 6f435c3d19..2448ce0578 100644 --- a/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs @@ -35,7 +35,7 @@ namespace Umbraco.Web.PropertyEditors //needs to be explicitly casted to Dictionary macroAttributes.ConvertTo(x => (string)x, x => (object)x)).ToString())); - return new Attempt(true, new HtmlString(sb.ToString())); + return Attempt.Succ(new HtmlString(sb.ToString())); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index a1482c08e1..79f029c4a7 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -262,7 +262,7 @@ namespace Umbraco.Web reason = EnsureRoutableOutcome.NoContent; } - return new Attempt(reason == EnsureRoutableOutcome.IsRoutable, reason); + return Attempt.If(reason == EnsureRoutableOutcome.IsRoutable, reason); } /// diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index b8ba3f9a7b..ca334d6371 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -35,15 +35,15 @@ namespace Umbraco.Web.WebApi var httpContext = context as HttpContextBase; if (httpContext != null) { - return new Attempt(true, httpContext); + return Attempt.Succ(httpContext); } } if (HttpContext.Current != null) { - return new Attempt(true, new HttpContextWrapper(HttpContext.Current)); + return Attempt.Succ(new HttpContextWrapper(HttpContext.Current)); } - return Attempt.False; + return Attempt.Fail(); } /// diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs index d804f97899..5ffacf8bfb 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs @@ -649,7 +649,7 @@ namespace umbraco.MacroEngines { try { - return new Attempt(true, + return Attempt.Succ( n.GetType().InvokeMember(memberAlias, System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | @@ -660,7 +660,7 @@ namespace umbraco.MacroEngines } catch (MissingMethodException ex) { - return new Attempt(ex); + return Attempt.Fail(ex); } }; diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 66e6db5080..072d830e27 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -900,10 +900,7 @@ namespace umbraco.cms.businesslogic.web [Obsolete("Don't use! Only used internally to support the legacy events", false)] internal Attempt SaveAndPublish(int userId) { - var result = new Attempt(false, - new PublishStatus(Content, - PublishStatusType - .FailedCancelledByEvent)); + var result = Attempt.Fail(new PublishStatus(Content, PublishStatusType.FailedCancelledByEvent)); foreach (var property in GenericProperties) { Content.SetValue(property.PropertyType.Alias, property.Value); @@ -1028,10 +1025,10 @@ namespace umbraco.cms.businesslogic.web return result; } - return Attempt.False; + return Attempt.Fail(); } - return Attempt.False; + return Attempt.Fail(); } /// From 9ca048f0ade73cb28e6d2f947533fc040f146b9c Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 5 Sep 2013 13:34:43 +0200 Subject: [PATCH 13/58] Core.Attempt - maintain backward compatibility --- src/Umbraco.Core/Attempt{T}.cs | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Umbraco.Core/Attempt{T}.cs b/src/Umbraco.Core/Attempt{T}.cs index a5dce955c7..c1f88cab20 100644 --- a/src/Umbraco.Core/Attempt{T}.cs +++ b/src/Umbraco.Core/Attempt{T}.cs @@ -27,6 +27,13 @@ namespace Umbraco.Core /// public Exception Exception { get { return _exception; } } + /// + /// Gets the exception associated with an unsuccessful attempt. + /// + /// Keep it for backward compatibility sake. + [Obsolete(".Error is obsolete, you should use .Exception instead.", false)] + public Exception Error { get { return _exception; } } + /// /// Gets the attempt result. /// @@ -38,6 +45,13 @@ namespace Umbraco.Core // optimize, use a singleton failed attempt private static readonly Attempt Failed = new Attempt(false, default(T), null); + /// + /// Represents an unsuccessful attempt. + /// + /// Keep it for backward compatibility sake. + [Obsolete(".Failed is obsolete, you should use Attempt.Fail() instead.", false)] + public static readonly Attempt False = Failed; + // private - use Succ() or Fail() methods to create attempts private Attempt(bool success, T result, Exception exception) { @@ -46,6 +60,27 @@ namespace Umbraco.Core _exception = exception; } + /// + /// Initialize a new instance of the struct with a result. + /// + /// A value indicating whether the attempt is successful. + /// The result of the attempt. + /// Keep it for backward compatibility sake. + [Obsolete("Attempt ctors are obsolete, you should use Attempt.Succ(), Attempt.Fail() or Attempt.If() instead.", false)] + public Attempt(bool success, T result) + : this(success, result, null) + { } + + /// + /// Initialize a new instance of the struct representing a failed attempt, with an exception. + /// + /// The exception causing the failure of the attempt. + /// Keep it for backward compatibility sake. + [Obsolete("Attempt ctors are obsolete, you should use Attempt.Succ(), Attempt.Fail() or Attempt.If() instead.", false)] + public Attempt(Exception exception) + : this(false, default(T), exception) + { } + /// /// Creates a successful attempt. /// From 9f1d212375058cd784e6bdaf6dddf8527be8cb70 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 11 Sep 2013 11:57:15 +1000 Subject: [PATCH 14/58] Implements: U4-2824 Type Converter for string type with unit test --- src/Umbraco.Core/ObjectExtensions.cs | 3 +++ src/Umbraco.Tests/ObjectExtensionsTests.cs | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 434f71cb18..5bc8e46161 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -83,6 +83,9 @@ namespace Umbraco.Core if (input.GetType() == destinationType) return new Attempt(true, input); + //check for string so that overloaders of ToString() can take advantage of the conversion. + if (destinationType == typeof(string)) return new Attempt(true, input.ToString()); + if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>)) { //TODO: Do a check for destination type being IEnumerable and source type implementing IEnumerable with diff --git a/src/Umbraco.Tests/ObjectExtensionsTests.cs b/src/Umbraco.Tests/ObjectExtensionsTests.cs index 788a28c4f4..6829e61a4f 100644 --- a/src/Umbraco.Tests/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests/ObjectExtensionsTests.cs @@ -115,7 +115,16 @@ namespace Umbraco.Tests } } - /// + [Test] + public virtual void CanConvertObjectToString_Using_ToString_Overload() + { + var result = new MyTestObject().TryConvertTo(); + + Assert.IsTrue(result.Success); + Assert.AreEqual("Hello world", result.Result); + } + + /// /// Run once before each test in derived test fixtures. /// public override void TestSetup() @@ -130,5 +139,13 @@ namespace Umbraco.Tests { return; } + + private class MyTestObject + { + public override string ToString() + { + return "Hello world"; + } + } } } \ No newline at end of file From 90abe8c25f867bdc20622ef9bda82f949f9062ef Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 11 Sep 2013 12:15:29 +1000 Subject: [PATCH 15/58] Fixes: U4-2823 RenderRouteHandler.GetUmbracoRouteDefinition() fails to store the route definition when an incidental alias-controller match is made --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- src/Umbraco.Web/Mvc/RenderRouteHandler.cs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index f9d60fbacb..02ddb3454b 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2608,8 +2608,8 @@ - - + + diff --git a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs index 1ebfebf1e4..56c4059f95 100644 --- a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs +++ b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs @@ -305,8 +305,9 @@ namespace Umbraco.Web.Mvc () => controllerType.FullName, () => typeof(IRenderMvcController).FullName, () => typeof(ControllerBase).FullName); - //exit as we cannnot route to the custom controller, just route to the standard one. - return def; + + //we cannot route to this custom controller since it is not of the correct type so we'll continue with the defaults + // that have already been set above. } } From 32e3048717065d2f0e94b600a597bcf1aac5b9a4 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 11 Sep 2013 08:22:28 +0200 Subject: [PATCH 16/58] Core.Attempt - refactor Succ() into Succeed() --- src/Umbraco.Core/Attempt.cs | 6 ++--- src/Umbraco.Core/Attempt{T}.cs | 22 +++++++++---------- .../Dynamics/DynamicInstanceHelper.cs | 6 ++--- src/Umbraco.Core/Dynamics/DynamicXml.cs | 8 +++---- src/Umbraco.Core/ObjectExtensions.cs | 20 ++++++++--------- .../Persistence/Mappers/MappingResolver.cs | 2 +- .../Repositories/RepositoryBase.cs | 2 +- src/Umbraco.Core/PluginManager.cs | 2 +- src/Umbraco.Core/Profiling/WebProfiler.cs | 2 +- .../TinyMcePropertyEditorValueConverter.cs | 2 +- src/Umbraco.Core/PublishedContentHelper.cs | 10 ++++----- .../Publishing/PublishingStrategy.cs | 8 +++---- src/Umbraco.Core/TypeHelper.cs | 4 ++-- .../Models/DynamicPublishedContent.cs | 10 ++++----- src/Umbraco.Web/Mvc/SurfaceController.cs | 2 +- ...roRenderingPropertyEditorValueConverter.cs | 2 +- .../WebApi/UmbracoApiController.cs | 4 ++-- .../RazorDynamicNode/DynamicNode.cs | 2 +- 18 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/Umbraco.Core/Attempt.cs b/src/Umbraco.Core/Attempt.cs index ed7c978b52..f87c46c6a3 100644 --- a/src/Umbraco.Core/Attempt.cs +++ b/src/Umbraco.Core/Attempt.cs @@ -13,9 +13,9 @@ namespace Umbraco.Core /// The type of the attempted operation result. /// The result of the attempt. /// The successful attempt. - public static Attempt Succ(T result) + public static Attempt Succeed(T result) { - return Attempt.Succ(result); + return Attempt.Succeed(result); } /// @@ -50,7 +50,7 @@ namespace Umbraco.Core /// The attempt. public static Attempt If(bool success, T result) { - return Attempt.If(success, result); + return Attempt.SucceedIf(success, result); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Attempt{T}.cs b/src/Umbraco.Core/Attempt{T}.cs index c1f88cab20..4a348247d4 100644 --- a/src/Umbraco.Core/Attempt{T}.cs +++ b/src/Umbraco.Core/Attempt{T}.cs @@ -52,7 +52,7 @@ namespace Umbraco.Core [Obsolete(".Failed is obsolete, you should use Attempt.Fail() instead.", false)] public static readonly Attempt False = Failed; - // private - use Succ() or Fail() methods to create attempts + // private - use Succeed() or Fail() methods to create attempts private Attempt(bool success, T result, Exception exception) { _success = success; @@ -66,7 +66,7 @@ namespace Umbraco.Core /// A value indicating whether the attempt is successful. /// The result of the attempt. /// Keep it for backward compatibility sake. - [Obsolete("Attempt ctors are obsolete, you should use Attempt.Succ(), Attempt.Fail() or Attempt.If() instead.", false)] + [Obsolete("Attempt ctors are obsolete, you should use Attempt.Succeed(), Attempt.Fail() or Attempt.If() instead.", false)] public Attempt(bool success, T result) : this(success, result, null) { } @@ -76,7 +76,7 @@ namespace Umbraco.Core /// /// The exception causing the failure of the attempt. /// Keep it for backward compatibility sake. - [Obsolete("Attempt ctors are obsolete, you should use Attempt.Succ(), Attempt.Fail() or Attempt.If() instead.", false)] + [Obsolete("Attempt ctors are obsolete, you should use Attempt.Succeed(), Attempt.Fail() or Attempt.If() instead.", false)] public Attempt(Exception exception) : this(false, default(T), exception) { } @@ -85,7 +85,7 @@ namespace Umbraco.Core /// Creates a successful attempt. /// /// The successful attempt. - public static Attempt Succ() + public static Attempt Succeed() { return new Attempt(true, default(T), null); } @@ -95,7 +95,7 @@ namespace Umbraco.Core /// /// The result of the attempt. /// The successful attempt. - public static Attempt Succ(T result) + public static Attempt Succeed(T result) { return new Attempt(true, result, null); } @@ -143,22 +143,22 @@ namespace Umbraco.Core /// /// Creates a successful or a failed attempt. /// - /// A value indicating whether the attempt is successful. + /// A value indicating whether the attempt is successful. /// The attempt. - public static Attempt If(bool success) + public static Attempt SucceedIf(bool condition) { - return success ? new Attempt(true, default(T), null) : Failed; + return condition ? new Attempt(true, default(T), null) : Failed; } /// /// Creates a successful or a failed attempt, with a result. /// - /// A value indicating whether the attempt is successful. + /// A value indicating whether the attempt is successful. /// The result of the attempt. /// The attempt. - public static Attempt If(bool success, T result) + public static Attempt SucceedIf(bool condition, T result) { - return new Attempt(success, result, null); + return new Attempt(condition, result, null); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs index b0e5981bff..1338ee03e2 100644 --- a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs +++ b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs @@ -82,7 +82,7 @@ namespace Umbraco.Core.Dynamics null, thisObject, args); - return Attempt.Succ(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty)); + return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty)); } catch (MissingMethodException) { @@ -97,7 +97,7 @@ namespace Umbraco.Core.Dynamics null, thisObject, args); - return Attempt.Succ(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod)); + return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod)); } catch (MissingMethodException) { @@ -106,7 +106,7 @@ namespace Umbraco.Core.Dynamics try { result = FindAndExecuteExtensionMethod(thisObject, args, binder.Name, findExtensionMethodsOnTypes); - return Attempt.Succ(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod)); + return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod)); } catch (TargetInvocationException ext) { diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs index 0e02e44db9..a84389d2e5 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXml.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXml.cs @@ -261,7 +261,7 @@ namespace Umbraco.Core.Dynamics var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray(); if (attributes.Any()) { - return Attempt>.Succ(attributes); + return Attempt>.Succeed(attributes); } if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) @@ -271,7 +271,7 @@ namespace Umbraco.Core.Dynamics if (childElements.Any()) { //we've found a match by the first child of an element called 'root' (strange, but sure) - return Attempt>.Succ(childElements); + return Attempt>.Succeed(childElements); } } @@ -293,7 +293,7 @@ namespace Umbraco.Core.Dynamics //Check if we've got any matches, if so then return true if (elements.Any()) { - return Attempt>.Succ(elements); + return Attempt>.Succeed(elements); } if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) @@ -303,7 +303,7 @@ namespace Umbraco.Core.Dynamics if (childElements.Any()) { //we've found a match by the first child of an element called 'root' (strange, but sure) - return Attempt>.Succ(childElements); + return Attempt>.Succeed(childElements); } } diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 7726af50ff..40708d0fc4 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -58,14 +58,14 @@ namespace Umbraco.Core try { var converted = (T) input; - return Attempt.Succ(converted); + return Attempt.Succeed(converted); } catch (Exception e) { return Attempt.Fail(e); } } - return !result.Success ? Attempt.Fail() : Attempt.Succ((T)result.Result); + return !result.Success ? Attempt.Fail() : Attempt.Succeed((T)result.Result); } /// @@ -79,9 +79,9 @@ namespace Umbraco.Core { if (input == null) return Attempt.Fail(); - if (destinationType == typeof(object)) return Attempt.Succ(input); + if (destinationType == typeof(object)) return Attempt.Succeed(input); - if (input.GetType() == destinationType) return Attempt.Succ(input); + if (input.GetType() == destinationType) return Attempt.Succeed(input); if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>)) { @@ -94,7 +94,7 @@ namespace Umbraco.Core try { var casted = Convert.ChangeType(input, destinationType); - return Attempt.Succ(casted); + return Attempt.Succeed(casted); } catch (Exception e) { @@ -109,7 +109,7 @@ namespace Umbraco.Core try { var converted = inputConverter.ConvertTo(input, destinationType); - return Attempt.Succ(converted); + return Attempt.Succeed(converted); } catch (Exception e) { @@ -125,7 +125,7 @@ namespace Umbraco.Core try { var converted = boolConverter.ConvertFrom(input); - return Attempt.Succ(converted); + return Attempt.Succeed(converted); } catch (Exception e) { @@ -140,7 +140,7 @@ namespace Umbraco.Core try { var converted = outputConverter.ConvertFrom(input); - return Attempt.Succ(converted); + return Attempt.Succeed(converted); } catch (Exception e) { @@ -154,7 +154,7 @@ namespace Umbraco.Core try { var casted = Convert.ChangeType(input, destinationType); - return Attempt.Succ(casted); + return Attempt.Succeed(casted); } catch (Exception e) { @@ -351,7 +351,7 @@ namespace Umbraco.Core try { var output = value.ToXmlString(type); - return Attempt.Succ(output); + return Attempt.Succeed(output); } catch (NotSupportedException ex) { diff --git a/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs b/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs index 8c576f1e63..4b6b513bf2 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MappingResolver.cs @@ -73,7 +73,7 @@ namespace Umbraco.Core.Persistence.Mappers { var instance = Activator.CreateInstance(mapper) as BaseMapper; return instance != null - ? Attempt.Succ(instance) + ? Attempt.Succeed(instance) : Attempt.Fail(); } catch (Exception ex) diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index b9f20cd706..26e97beff7 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -117,7 +117,7 @@ namespace Umbraco.Core.Persistence.Repositories var rEntity = _cache.GetById(typeof(TEntity), key); if (rEntity != null) { - return Attempt.Succ((TEntity) rEntity); + return Attempt.Succeed((TEntity) rEntity); } return Attempt.Fail(); } diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index 1db052396a..485602f23f 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -275,7 +275,7 @@ namespace Umbraco.Core return Attempt>.Fail(new CachedPluginNotFoundInFile()); //return success - return Attempt.Succ(typeElement.Elements("add") + return Attempt.Succeed(typeElement.Elements("add") .Select(x => (string)x.Attribute("type"))); } catch (Exception ex) diff --git a/src/Umbraco.Core/Profiling/WebProfiler.cs b/src/Umbraco.Core/Profiling/WebProfiler.cs index 6dae4cde0c..d3fd0daae0 100644 --- a/src/Umbraco.Core/Profiling/WebProfiler.cs +++ b/src/Umbraco.Core/Profiling/WebProfiler.cs @@ -148,7 +148,7 @@ namespace Umbraco.Core.Profiling try { var req = app.Request; - return Attempt.Succ(new HttpRequestWrapper(req)); + return Attempt.Succeed(new HttpRequestWrapper(req)); } catch (HttpException ex) { diff --git a/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs b/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs index e6acbf36e0..8480d91260 100644 --- a/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.PropertyEditors /// public virtual Attempt ConvertPropertyValue(object value) { - return Attempt.Succ(new HtmlString(value.ToString())); + return Attempt.Succeed(new HtmlString(value.ToString())); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/PublishedContentHelper.cs b/src/Umbraco.Core/PublishedContentHelper.cs index db8d2dbbe4..6dffef290d 100644 --- a/src/Umbraco.Core/PublishedContentHelper.cs +++ b/src/Umbraco.Core/PublishedContentHelper.cs @@ -105,7 +105,7 @@ namespace Umbraco.Core .Select(p => p.ConvertPropertyValue(currentValue)) .Where(converted => converted.Success)) { - return Attempt.Succ(converted.Result); + return Attempt.Succeed(converted.Result); } //if none of the converters worked, then we'll process this from what we know @@ -118,17 +118,17 @@ namespace Umbraco.Core decimal dResult; if (decimal.TryParse(sResult, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.CurrentCulture, out dResult)) { - return Attempt.Succ(dResult); + return Attempt.Succeed(dResult); } } //process string booleans as booleans if (sResult.InvariantEquals("true")) { - return Attempt.Succ(true); + return Attempt.Succeed(true); } if (sResult.InvariantEquals("false")) { - return Attempt.Succ(false); + return Attempt.Succeed(false); } //a really rough check to see if this may be valid xml @@ -147,7 +147,7 @@ namespace Umbraco.Core if (!UmbracoSettings.NotDynamicXmlDocumentElements.Any( tag => string.Equals(tag, documentElement, StringComparison.CurrentCultureIgnoreCase))) { - return Attempt.Succ(new DynamicXml(e)); + return Attempt.Succeed(new DynamicXml(e)); } return Attempt.Fail(); } diff --git a/src/Umbraco.Core/Publishing/PublishingStrategy.cs b/src/Umbraco.Core/Publishing/PublishingStrategy.cs index d115bb1a10..899567bf8d 100644 --- a/src/Umbraco.Core/Publishing/PublishingStrategy.cs +++ b/src/Umbraco.Core/Publishing/PublishingStrategy.cs @@ -62,7 +62,7 @@ namespace Umbraco.Core.Publishing string.Format("Content '{0}' with Id '{1}' has been published.", content.Name, content.Id)); - return Attempt.Succ(new PublishStatus(content)); + return Attempt.Succeed(new PublishStatus(content)); } /// @@ -125,7 +125,7 @@ namespace Umbraco.Core.Publishing //We're going to populate the statuses with all content that is already published because below we are only going to iterate over // content that is not published. We'll set the status to "AlreadyPublished" statuses.AddRange(fetchedContent.Where(x => x.Published) - .Select(x => Attempt.Succ(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished)))); + .Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished)))); int? firstLevel = null; @@ -239,7 +239,7 @@ namespace Umbraco.Core.Publishing string.Format("Content '{0}' with Id '{1}' has been published.", item.Name, item.Id)); - statuses.Add(Attempt.Succ(new PublishStatus(item))); + statuses.Add(Attempt.Succeed(new PublishStatus(item))); } } @@ -370,7 +370,7 @@ namespace Umbraco.Core.Publishing string.Format("Content '{0}' with Id '{1}' has been unpublished.", item.Name, item.Id)); - result.Add(Attempt.Succ(new PublishStatus(item))); + result.Add(Attempt.Succeed(new PublishStatus(item))); } return result; diff --git a/src/Umbraco.Core/TypeHelper.cs b/src/Umbraco.Core/TypeHelper.cs index 71e558e55c..e77f03ee78 100644 --- a/src/Umbraco.Core/TypeHelper.cs +++ b/src/Umbraco.Core/TypeHelper.cs @@ -99,7 +99,7 @@ namespace Umbraco.Core } if (types.Length == 1) { - return Attempt.Succ(types[0]); + return Attempt.Succeed(types[0]); } foreach (var curr in types) @@ -112,7 +112,7 @@ namespace Umbraco.Core //if this type is the base for all others if (isBase) { - return Attempt.Succ(curr); + return Attempt.Succeed(curr); } } diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index 57f5981385..2d17ee11c0 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -150,7 +150,7 @@ namespace Umbraco.Web.Models { if (binder.Name.InvariantEquals("ChildrenAsList") || binder.Name.InvariantEquals("Children")) { - return Attempt.Succ(Children); + return Attempt.Succeed(Children); } if (binder.Name.InvariantEquals("parentId")) @@ -160,7 +160,7 @@ namespace Umbraco.Web.Models { throw new InvalidOperationException(string.Format("The node {0} does not have a parent", Id)); } - return Attempt.Succ(parent.Id); + return Attempt.Succeed(parent.Id); } return Attempt.Fail(); } @@ -182,7 +182,7 @@ namespace Umbraco.Web.Models .ToArray(); if (filteredTypeChildren.Any()) { - return Attempt.Succ( + return Attempt.Succeed( new DynamicPublishedContentList(filteredTypeChildren.Select(x => new DynamicPublishedContent(x)))); } return Attempt.Fail(); @@ -247,7 +247,7 @@ namespace Umbraco.Web.Models result = converted.Result; } - return Attempt.Succ(result); + return Attempt.Succeed(result); } @@ -382,7 +382,7 @@ namespace Umbraco.Web.Models { try { - return Attempt.Succ( + return Attempt.Succeed( content.GetType().InvokeMember(memberAlias, System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs index 0011718b3c..4aa2052519 100644 --- a/src/Umbraco.Web/Mvc/SurfaceController.cs +++ b/src/Umbraco.Web/Mvc/SurfaceController.cs @@ -105,7 +105,7 @@ namespace Umbraco.Web.Mvc var currentRouteData = currentContext.RouteData; if (currentRouteData.DataTokens.ContainsKey("umbraco-route-def")) { - return Attempt.Succ((RouteDefinition) currentRouteData.DataTokens["umbraco-route-def"]); + return Attempt.Succeed((RouteDefinition) currentRouteData.DataTokens["umbraco-route-def"]); } if (currentContext.IsChildAction) { diff --git a/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs b/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs index 2448ce0578..ee59ea6e94 100644 --- a/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs @@ -35,7 +35,7 @@ namespace Umbraco.Web.PropertyEditors //needs to be explicitly casted to Dictionary macroAttributes.ConvertTo(x => (string)x, x => (object)x)).ToString())); - return Attempt.Succ(new HtmlString(sb.ToString())); + return Attempt.Succeed(new HtmlString(sb.ToString())); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index ca334d6371..bf25dc0e7c 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -35,12 +35,12 @@ namespace Umbraco.Web.WebApi var httpContext = context as HttpContextBase; if (httpContext != null) { - return Attempt.Succ(httpContext); + return Attempt.Succeed(httpContext); } } if (HttpContext.Current != null) { - return Attempt.Succ(new HttpContextWrapper(HttpContext.Current)); + return Attempt.Succeed(new HttpContextWrapper(HttpContext.Current)); } return Attempt.Fail(); diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs index 5ffacf8bfb..a2ac541247 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs @@ -649,7 +649,7 @@ namespace umbraco.MacroEngines { try { - return Attempt.Succ( + return Attempt.Succeed( n.GetType().InvokeMember(memberAlias, System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | From 82f81d1f4f470198d2fa0159bb18657355c71959 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 11 Sep 2013 09:28:01 +0200 Subject: [PATCH 17/58] Core.Attempt - backport and refactor Attempt.Outcome from v7 --- src/Umbraco.Core/Attempt.cs | 110 +++++++++++++++++++++++++ src/Umbraco.Tests/AttemptTests.cs | 41 +++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 3 files changed, 152 insertions(+) create mode 100644 src/Umbraco.Tests/AttemptTests.cs diff --git a/src/Umbraco.Core/Attempt.cs b/src/Umbraco.Core/Attempt.cs index f87c46c6a3..ca2bbe35fe 100644 --- a/src/Umbraco.Core/Attempt.cs +++ b/src/Umbraco.Core/Attempt.cs @@ -52,5 +52,115 @@ namespace Umbraco.Core { return Attempt.SucceedIf(success, result); } + + + /// + /// Executes an attempt function, with callbacks. + /// + /// The type of the attempted operation result. + /// The attempt returned by the attempt function. + /// An action to execute in case the attempt succeeds. + /// An action to execute in case the attempt fails. + /// The outcome of the attempt. + /// Runs or depending on the + /// whether the attempt function reports a success or a failure. + public static Outcome Try(Attempt attempt, Action onSuccess, Action onFail = null) + { + if (attempt.Success) + { + onSuccess(attempt.Result); + return Outcome.Success; + } + + if (onFail != null) + { + onFail(attempt.Exception); + } + + return Outcome.Failure; + } + + /// + /// Represents the outcome of an attempt. + /// + /// Can be a success or a failure, and allows for attempts chaining. + public struct Outcome + { + private readonly bool _success; + + /// + /// Gets an outcome representing a success. + /// + public static readonly Outcome Success = new Outcome(true); + + /// + /// Gets an outcome representing a failure. + /// + public static readonly Outcome Failure = new Outcome(false); + + private Outcome(bool success) + { + _success = success; + } + + /// + /// Executes another attempt function, if the previous one failed, with callbacks. + /// + /// The type of the attempted operation result. + /// The attempt function to execute, returning an attempt. + /// An action to execute in case the attempt succeeds. + /// An action to execute in case the attempt fails. + /// If it executes, returns the outcome of the attempt, else returns a success outcome. + /// + /// Executes only if the previous attempt failed, else does not execute and return a success outcome. + /// If it executes, then runs or depending on the + /// whether the attempt function reports a success or a failure. + /// + public Outcome OnFailure(Func> nextFunction, Action onSuccess, Action onFail = null) + { + return _success + ? Success + : ExecuteNextFunction(nextFunction, onSuccess, onFail); + } + + /// + /// Executes another attempt function, if the previous one succeeded, with callbacks. + /// + /// The type of the attempted operation result. + /// The attempt function to execute, returning an attempt. + /// An action to execute in case the attempt succeeds. + /// An action to execute in case the attempt fails. + /// If it executes, returns the outcome of the attempt, else returns a failed outcome. + /// + /// Executes only if the previous attempt succeeded, else does not execute and return a success outcome. + /// If it executes, then runs or depending on the + /// whether the attempt function reports a success or a failure. + /// + public Outcome OnSuccess(Func> nextFunction, Action onSuccess, Action onFail = null) + { + return _success + ? ExecuteNextFunction(nextFunction, onSuccess, onFail) + : Failure; + } + + private static Outcome ExecuteNextFunction(Func> nextFunction, Action onSuccess, Action onFail = null) + { + var attempt = nextFunction(); + + if (attempt.Success) + { + onSuccess(attempt.Result); + return Success; + } + + if (onFail != null) + { + onFail(attempt.Exception); + } + + return Failure; + } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/AttemptTests.cs b/src/Umbraco.Tests/AttemptTests.cs new file mode 100644 index 0000000000..04da490664 --- /dev/null +++ b/src/Umbraco.Tests/AttemptTests.cs @@ -0,0 +1,41 @@ +using System; +using NUnit.Framework; +using Umbraco.Core; + +namespace Umbraco.Tests +{ + [TestFixture] + public class AttemptTests + { + [Test] + public void Chained_Attempts() + { + Attempt.Try(Attempt.Succeed("success!"), + s => Assert.AreEqual("success!", s), + exception => Assert.Fail("Should have been successful.")) + + // previous one was a success so that one SHOULD NOT run + // and report success + .OnFailure(() => Attempt.Succeed(123), + i => Assert.Fail("The previous attempt was successful!"), + exception => Assert.Fail("The previous attempt was successful!")) + + // previous one did not run, last run was a success so that one SHOULD run + // and report failure + .OnSuccess(() => Attempt.Fail(new Exception("Failed!")), + d => Assert.Fail("Should have failed."), + exception => Assert.AreEqual("Failed!", exception.Message)) + + // previous one did run and was a failure so that one SHOULD NOT run + .OnSuccess(() => Attempt.Succeed(987), + i => Assert.Fail("The previous attempt failed!"), + exception => Assert.Fail("The previous attempt failed!")) + + // previous one did not run, last run was a failure so that one SHOULD run + // then why does it run? + .OnFailure(() => Attempt.Succeed("finished"), + i => Assert.AreEqual("finished", i), + exception => Assert.Fail("Should have been successful.")); + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e9ac0dbc8f..bca5360d84 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -142,6 +142,7 @@ + From c5c44cec37a71fe5aba5e898e68e65372b733d92 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 11 Sep 2013 10:15:31 +0200 Subject: [PATCH 18/58] Correcting syntax output for AlterColumnExpression, so Shannon's migrations will work --- .../Syntax/Alter/Expressions/AlterColumnExpression.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs index db58b7f918..23c489b96b 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs @@ -21,9 +21,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions public override string ToString() { - return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn, - SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName), - SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name)); + string columnNameFormat = string.Format("{0} {1}", + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name), + SqlSyntaxContext.SqlSyntaxProvider.Format(Column)); + + return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn, + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName), + columnNameFormat); } } } \ No newline at end of file From 8d510fd512b2836a6e4ff7f35f0224815778aadc Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 11 Sep 2013 10:16:49 +0200 Subject: [PATCH 19/58] Committing some POC code in the test project for strongly typed models/queries --- .../StronglyTypedModels/Subpage.cs | 41 +++++ .../StronglyTypedModels/Textpage.cs | 60 +++++++ .../StronglyTypedModels/TextpageModel.cs | 20 --- .../StronglyTypedModels/TypedModelBase.cs | 170 ++++++++++++++++-- .../UmbracoTemplatePage`T.cs | 6 + src/Umbraco.Tests/Umbraco.Tests.csproj | 4 +- 6 files changed, 262 insertions(+), 39 deletions(-) create mode 100644 src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Subpage.cs create mode 100644 src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Textpage.cs delete mode 100644 src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TextpageModel.cs diff --git a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Subpage.cs b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Subpage.cs new file mode 100644 index 0000000000..57d1ee3492 --- /dev/null +++ b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Subpage.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; + +namespace Umbraco.Tests.PublishedContent.StronglyTypedModels +{ + /// + /// Represents a Subpage which acts as the strongly typed model for a Doc Type + /// with alias "Subpage" and "Subpage" as the allowed child type. + /// + /// Similar to the Textpage this model could also be generated, but it could also + /// act as a Code-First model by using the attributes shown on the various properties, + /// which decorate the model with information about the Document Type, its + /// Property Groups and Property Types. + /// + public class Subpage : TypedModelBase + { + public Subpage(IPublishedContent publishedContent) : base(publishedContent) + { + } + + public string Title { get { return Resolve(Property()); } } + + public string BodyText { get { return Resolve(Property()); } } + + public Textpage Parent + { + get + { + return Parent(); + } + } + + public IEnumerable Subpages + { + get + { + return Children(ContentTypeAlias()); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Textpage.cs b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Textpage.cs new file mode 100644 index 0000000000..fff1ae9107 --- /dev/null +++ b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/Textpage.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Models; + +namespace Umbraco.Tests.PublishedContent.StronglyTypedModels +{ + /// + /// Represents a Textpage which acts as the strongly typed model for a Doc Type + /// with alias "Textpage" and "Subpage" as the allowed child type. + /// + /// The basic properties are resolved by convention using the Resolve-Type-PropertyTypeAlias + /// convention available through the base class' protected Resolve-method and Property-delegate. + /// + /// The Textpage allows the use of Subpage and Textpage as child doc types, which are exposed as a + /// collection using the Children-Type-ContentTypeAlias convention available through the + /// base class' protected Children-method and ContentTypeAlias-delegate. + /// + /// + /// This code can easily be generated using simple conventions for the types and names + /// of the properties that this type of strongly typed model exposes. + /// + public class Textpage : TypedModelBase + { + public Textpage(IPublishedContent publishedContent) : base(publishedContent) + { + } + + public string Title { get { return Resolve(Property()); } } + + public string BodyText { get { return Resolve(Property()); } } + + public string AuthorName { get { return Resolve(Property()); } } + + public DateTime Date { get { return Resolve(Property()); } } + + public Textpage Parent + { + get + { + return Parent(); + } + } + + public IEnumerable Textpages + { + get + { + return Children(ContentTypeAlias()); + } + } + + public IEnumerable Subpages + { + get + { + return Children(ContentTypeAlias()); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TextpageModel.cs b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TextpageModel.cs deleted file mode 100644 index 47f2f817f1..0000000000 --- a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TextpageModel.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Umbraco.Core.Models; - -namespace Umbraco.Tests.PublishedContent.StronglyTypedModels -{ - public class TextpageModel : TypedModelBase - { - public TextpageModel(IPublishedContent publishedContent) : base(publishedContent) - { - } - - public string Title { get { return Resolve(Property(), DefaultString); } } - - public string BodyText { get { return Resolve(Property(), DefaultString); } } - - public string AuthorName { get { return Resolve(Property()); } } - - public DateTime Date { get { return Resolve(Property(), DefaultDateTime); } } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TypedModelBase.cs b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TypedModelBase.cs index 4cc6e2ebf2..d606be3c5b 100644 --- a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TypedModelBase.cs +++ b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/TypedModelBase.cs @@ -1,12 +1,34 @@ using System; +using System.Collections.Generic; +using System.Data.Entity.Design.PluralizationServices; +using System.Globalization; using System.Reflection; +using System.Linq; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Web; namespace Umbraco.Tests.PublishedContent.StronglyTypedModels { - public abstract class TypedModelBase + /// + /// Represents the abstract base class for a 'TypedModel', which basically wraps IPublishedContent + /// underneath a strongly typed model like "Textpage" and "Subpage". + /// Because IPublishedContent is used under the hood there is no need for additional mapping, so the + /// only added cost should be the creation of the objects, which the IPublishedContent instance is + /// passed into. + /// + /// This base class exposes a simple way to write property getters by convention without + /// using the string alias of a PropertyType (this is resolved by the use of the Property delegate). + /// + /// This base class also exposes query options like Parent, Children, Ancestors and Descendants, + /// which can be used for collections of strongly typed child models/objects. These types of collections + /// typically corresponds to 'allowed child content types' on a Doc Type (at different levels). + /// + /// The IPublishedContent properties are also exposed through this base class, but only + /// by casting the typed model to IPublishedContent, so the properties doesn't show up by default: + /// ie. ((IPublishedContent)textpage).Url + /// + public abstract class TypedModelBase : IPublishedContent { private readonly IPublishedContent _publishedContent; @@ -15,56 +37,168 @@ namespace Umbraco.Tests.PublishedContent.StronglyTypedModels _publishedContent = publishedContent; } - public readonly Func Property = MethodBase.GetCurrentMethod; - public static string DefaultString = default(string); - public static int DefaultInteger = default(int); - public static bool DefaultBool = default(bool); - public static DateTime DefaultDateTime = default(DateTime); + protected readonly Func Property = MethodBase.GetCurrentMethod; + protected readonly Func ContentTypeAlias = MethodBase.GetCurrentMethod; - public T Resolve(MethodBase methodBase) + #region Properties + + protected T Resolve(MethodBase methodBase) { var propertyTypeAlias = methodBase.ToUmbracoAlias(); + return Resolve(propertyTypeAlias); + } + + protected T Resolve(string propertyTypeAlias) + { return _publishedContent.GetPropertyValue(propertyTypeAlias); } - public T Resolve(MethodBase methodBase, T ifCannotConvert) + protected T Resolve(MethodBase methodBase, T ifCannotConvert) { var propertyTypeAlias = methodBase.ToUmbracoAlias(); + return Resolve(propertyTypeAlias, ifCannotConvert); + } + + protected T Resolve(string propertyTypeAlias, T ifCannotConvert) + { return _publishedContent.GetPropertyValue(propertyTypeAlias, false, ifCannotConvert); } - public T Resolve(MethodBase methodBase, bool recursive, T ifCannotConvert) + protected T Resolve(MethodBase methodBase, bool recursive, T ifCannotConvert) { var propertyTypeAlias = methodBase.ToUmbracoAlias(); + return Resolve(propertyTypeAlias, recursive, ifCannotConvert); + } + + protected T Resolve(string propertyTypeAlias, bool recursive, T ifCannotConvert) + { return _publishedContent.GetPropertyValue(propertyTypeAlias, recursive, ifCannotConvert); } + #endregion - public string ResolveString(MethodBase methodBase) + #region Querying + protected T Parent() where T : TypedModelBase { - return Resolve(methodBase); + var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) }); + if (constructorInfo == null) + throw new Exception("No valid constructor found"); + + return (T) constructorInfo.Invoke(new object[] {_publishedContent.Parent}); } - public int ResolveInt(MethodBase methodBase) + protected IEnumerable Children(MethodBase methodBase) where T : TypedModelBase { - return Resolve(methodBase); + var docTypeAlias = methodBase.CleanCallingMethodName(); + return Children(docTypeAlias); } - public bool ResolveBool(MethodBase methodBase) + protected IEnumerable Children(string docTypeAlias) where T : TypedModelBase { - return Resolve(methodBase); + var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) }); + if(constructorInfo == null) + throw new Exception("No valid constructor found"); + + string singularizedDocTypeAlias = docTypeAlias.ToSingular(); + + return _publishedContent.Children.Where(x => x.DocumentTypeAlias == singularizedDocTypeAlias) + .Select(x => (T)constructorInfo.Invoke(new object[] { x })); } - public DateTime ResolveDate(MethodBase methodBase) + protected IEnumerable Ancestors(MethodBase methodBase) where T : TypedModelBase { - return Resolve(methodBase); + var docTypeAlias = methodBase.CleanCallingMethodName(); + return Ancestors(docTypeAlias); } + + protected IEnumerable Ancestors(string docTypeAlias) where T : TypedModelBase + { + var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) }); + if (constructorInfo == null) + throw new Exception("No valid constructor found"); + + string singularizedDocTypeAlias = docTypeAlias.ToSingular(); + + return _publishedContent.Ancestors().Where(x => x.DocumentTypeAlias == singularizedDocTypeAlias) + .Select(x => (T)constructorInfo.Invoke(new object[] { x })); + } + + protected IEnumerable Descendants(MethodBase methodBase) where T : TypedModelBase + { + var docTypeAlias = methodBase.CleanCallingMethodName(); + return Descendants(docTypeAlias); + } + + protected IEnumerable Descendants(string docTypeAlias) where T : TypedModelBase + { + var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) }); + if (constructorInfo == null) + throw new Exception("No valid constructor found"); + + string singularizedDocTypeAlias = docTypeAlias.ToSingular(); + + return _publishedContent.Descendants().Where(x => x.DocumentTypeAlias == singularizedDocTypeAlias) + .Select(x => (T)constructorInfo.Invoke(new object[] { x })); + } + #endregion + + #region IPublishedContent + int IPublishedContent.Id { get { return _publishedContent.Id; } } + int IPublishedContent.TemplateId { get { return _publishedContent.TemplateId; } } + int IPublishedContent.SortOrder { get { return _publishedContent.SortOrder; } } + string IPublishedContent.Name { get { return _publishedContent.Name; } } + string IPublishedContent.UrlName { get { return _publishedContent.UrlName; } } + string IPublishedContent.DocumentTypeAlias { get { return _publishedContent.DocumentTypeAlias; } } + int IPublishedContent.DocumentTypeId { get { return _publishedContent.DocumentTypeId; } } + string IPublishedContent.WriterName { get { return _publishedContent.WriterName; } } + string IPublishedContent.CreatorName { get { return _publishedContent.CreatorName; } } + int IPublishedContent.WriterId { get { return _publishedContent.WriterId; } } + int IPublishedContent.CreatorId { get { return _publishedContent.CreatorId; } } + string IPublishedContent.Path { get { return _publishedContent.Path; } } + DateTime IPublishedContent.CreateDate { get { return _publishedContent.CreateDate; } } + DateTime IPublishedContent.UpdateDate { get { return _publishedContent.UpdateDate; } } + Guid IPublishedContent.Version { get { return _publishedContent.Version; } } + int IPublishedContent.Level { get { return _publishedContent.Level; } } + string IPublishedContent.Url { get { return _publishedContent.Url; } } + PublishedItemType IPublishedContent.ItemType { get { return _publishedContent.ItemType; } } + IPublishedContent IPublishedContent.Parent { get { return _publishedContent.Parent; } } + IEnumerable IPublishedContent.Children { get { return _publishedContent.Children; } } + + ICollection IPublishedContent.Properties { get { return _publishedContent.Properties; } } + + object IPublishedContent.this[string propertyAlias] { get { return _publishedContent[propertyAlias]; } } + + IPublishedContentProperty IPublishedContent.GetProperty(string alias) + { + return _publishedContent.GetProperty(alias); + } + #endregion } + /// + /// Extension methods for MethodBase, which are used to clean the name of the calling method "get_BodyText" + /// to "BodyText" and then make it camel case according to the UmbracoAlias convention "bodyText". + /// There is also a string extension for making plural words singular, which is used when going from + /// something like "Subpages" to "Subpage" for Children/Ancestors/Descendants Doc Type aliases. + /// public static class TypeExtensions { + public static string CleanCallingMethodName(this MethodBase methodBase) + { + return methodBase.Name.Replace("get_", ""); + } + public static string ToUmbracoAlias(this MethodBase methodBase) { - return methodBase.Name.Replace("get_", "").ToUmbracoAlias(); + return methodBase.CleanCallingMethodName().ToUmbracoAlias(); + } + + public static string ToSingular(this string pluralWord) + { + var service = PluralizationService.CreateService(new CultureInfo("en-US")); + if (service.IsPlural(pluralWord)) + return service.Singularize(pluralWord); + + return pluralWord; } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs index 6e27886b83..ae0a3c062e 100644 --- a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs +++ b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs @@ -3,6 +3,12 @@ using Umbraco.Web.Mvc; namespace Umbraco.Tests.PublishedContent.StronglyTypedModels { + /// + /// Represents a basic extension of the UmbracoTemplatePage, which allows you to specify + /// the type of a strongly typed model that inherits from TypedModelBase. + /// The model is exposed as TypedModel. + /// + /// Type of the model to create/expose public abstract class UmbracoTemplatePage : UmbracoTemplatePage where T : TypedModelBase { protected override void InitializePage() diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e9ac0dbc8f..032fcb8bfb 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -82,6 +82,7 @@ + True ..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll @@ -194,7 +195,8 @@ - + + From e69b043cfadbfde2bf90bb38d3001f80bf2a94c1 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 11 Sep 2013 10:24:05 +0200 Subject: [PATCH 20/58] Oops, double column is no good syntax... --- .../Syntax/Alter/Expressions/AlterColumnExpression.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs index 23c489b96b..1041fdb367 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs @@ -21,13 +21,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions public override string ToString() { - string columnNameFormat = string.Format("{0} {1}", - SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name), - SqlSyntaxContext.SqlSyntaxProvider.Format(Column)); - return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn, SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName), - columnNameFormat); + SqlSyntaxContext.SqlSyntaxProvider.Format(Column)); } } } \ No newline at end of file From f53a23553b585b0bfcade3d86b37e0f8643d0fe1 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 11 Sep 2013 11:06:14 +0200 Subject: [PATCH 21/58] Core.Attempt - replace calls to obsolete ctor --- src/Umbraco.Core/ObjectExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index bc6d5c771b..b707163255 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -84,7 +84,7 @@ namespace Umbraco.Core if (input.GetType() == destinationType) return Attempt.Succeed(input); //check for string so that overloaders of ToString() can take advantage of the conversion. - if (destinationType == typeof(string)) return new Attempt(true, input.ToString()); + if (destinationType == typeof(string)) return Attempt.Succeed(input.ToString()); if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>)) { From 4719caf653bade89cb703169ebcbb6ebffc0ded0 Mon Sep 17 00:00:00 2001 From: perploug Date: Wed, 11 Sep 2013 14:02:45 +0200 Subject: [PATCH 22/58] Changes span size on c# panel --- src/umbraco.controls/Panel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/umbraco.controls/Panel.cs b/src/umbraco.controls/Panel.cs index d0d9607ec1..df09ef2ef6 100644 --- a/src/umbraco.controls/Panel.cs +++ b/src/umbraco.controls/Panel.cs @@ -94,14 +94,14 @@ namespace umbraco.uicontrols header.Controls.Add(row); leftcol.TagName = "span"; - leftcol.Attributes.Add("class", "span4 umb-panel-header-meta"); + leftcol.Attributes.Add("class", "span8 umb-panel-header-meta"); title.TagName = "h1"; leftcol.Controls.Add(title); row.Controls.Add(leftcol); rightcol.TagName = "span"; - rightcol.Attributes.Add("class", "span8 umb-panel-header-meta"); + rightcol.Attributes.Add("class", "span4 umb-panel-header-meta"); rightcol.Controls.Add(Menu); row.Controls.Add(rightcol); From 998e8bf9bdf4670861d3b6d0075dc3144280a0a6 Mon Sep 17 00:00:00 2001 From: perploug Date: Wed, 11 Sep 2013 14:03:13 +0200 Subject: [PATCH 23/58] Updates header css class to include padding --- src/Umbraco.Web.UI.Client/src/less/main.less | 10 ---------- src/Umbraco.Web.UI.Client/src/less/panel.less | 3 +-- .../src/views/directives/umb-contextmenu.html | 2 +- .../src/views/directives/umb-navigation.html | 2 +- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 226dc40a06..222b4493aa 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -146,17 +146,7 @@ div.umb-codeeditor .umb-btn-toolbar { margin: auto } -small.umb-detail, -label small { - color: #b3b3b3 !important; - text-decoration: none; - display: block; - font-weight: normal -} -label { - padding-top: 8px !important; -} /* FORM GRID */ diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less index 7d64cd3065..f3cfe80aed 100644 --- a/src/Umbraco.Web.UI.Client/src/less/panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/panel.less @@ -18,8 +18,7 @@ .umb-panel-header h1.umb-headline-editor { cursor: text; } - -.umb-headline-editor-wrapper{height: 50px;} +.umb-headline-editor-wrapper, .umb-panel-header-meta{height: 40px; padding-top: 10px;} .umb-headline-editor-wrapper h1, h1.headline { margin: 0; font-size: @fontSizeLarge; diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-contextmenu.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-contextmenu.html index dc16d0ed1f..4568335b50 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-contextmenu.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-contextmenu.html @@ -3,7 +3,7 @@ ng-show="nav.ui.showContextMenu" ng-animate="'slide'">
-

{{nav.ui.dialogTitle}}

+

{{nav.ui.dialogTitle}}

diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html index 7963327d81..5326b46d63 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html @@ -82,7 +82,7 @@ ng-swipe-left="nav.hideDialog()" ng-show="nav.ui.showContextMenuDialog" ng-animate="'slide'">
-

{{nav.ui.dialogTitle}}

+

{{nav.ui.dialogTitle}}

From c3e67a2144923daedd97eec58a3a769d6c409e46 Mon Sep 17 00:00:00 2001 From: perploug Date: Wed, 11 Sep 2013 14:03:28 +0200 Subject: [PATCH 24/58] chore: less cleanup --- src/Umbraco.Web.UI.Client/src/less/forms.less | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index e7ae20e154..3232b87943 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -11,6 +11,19 @@ margin-left: 0px !Important; } +small.umb-detail, +label small { + color: #b3b3b3 !important; + text-decoration: none; + display: block; + font-weight: normal +} +label.control-label { + padding-top: 8px !important; +} + +.controls-row label{padding: 0px 10px 0px 10px; vertical-align: center} + //utill styll to hide child untill hover .hover-show{visibility: hidden;} *:hover > .hover-show{visibility: visible;} From 377d72b5da3b5277a4b472707cc0b427cab9de62 Mon Sep 17 00:00:00 2001 From: perploug Date: Wed, 11 Sep 2013 14:03:59 +0200 Subject: [PATCH 25/58] better handling of closing dialogs --- .../src/common/services/dialog.service.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js b/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js index 40407d69db..cba96c9c28 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js @@ -101,13 +101,15 @@ angular.module('umbraco.services') }; scope.close = function(data) { - if (dialog.closeCallback) { + if (dialog.closeCallback) { dialog.closeCallback(data); - } + } - dialog.element.modal('hide'); - dialog.element.remove(); - $("#" + dialog.element.attr("id")).remove(); + if(dialog.element){ + dialog.element.modal('hide'); + dialog.element.remove(); + $("#" + dialog.element.attr("id")).remove(); + } }; //if iframe is enabled, inject that instead of a template @@ -260,8 +262,10 @@ angular.module('umbraco.services') * @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs. */ close: function (dialog, args) { - dialog.scope.close(); - + if(dialog && dialog.scope){ + dialog.scope.close(); + } + //removeDialog(dialog, args); }, From 76426194076dde332d03fad4d500bc742b6e1d22 Mon Sep 17 00:00:00 2001 From: perploug Date: Wed, 11 Sep 2013 14:04:26 +0200 Subject: [PATCH 26/58] Updating legacy edtors in developer section --- .../Umbraco/create/PartialView.ascx | 43 ++++++++------- .../create/PartialView.ascx.designer.cs | 31 +++++++---- .../umbraco/create/DLRScripting.ascx | 52 +++++++++++-------- src/Umbraco.Web.UI/umbraco/create/xslt.ascx | 39 ++++++++------ .../umbraco/developer/Macros/editMacro.aspx | 2 +- .../RelationTypes/EditRelationType.aspx | 4 +- .../umbraco/create/DLRScripting.ascx | 52 +++++++++++-------- .../create/DLRScripting.ascx.designer.cs | 39 +++++++------- .../umbraco/create/xslt.ascx | 38 ++++++++------ .../umbraco/create/xslt.ascx.designer.cs | 21 ++++---- .../RelationTypes/EditRelationType.aspx.cs | 15 +++--- 11 files changed, 184 insertions(+), 152 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx index d08c2ef062..87bd5d2eab 100644 --- a/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx +++ b/src/Umbraco.Web.UI/Umbraco/create/PartialView.ascx @@ -1,27 +1,30 @@ <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="PartialView.ascx.cs" Inherits="Umbraco.Web.UI.Umbraco.Create.PartialView" %> <%@ Import Namespace="umbraco" %> -<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> +<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> - + + + + * + -Filename (without .cshtml): -* + + + Clean + + + + + + + -<%----%> -
- -
-
- Choose a template:
- -
+ +