From 0987b2d646cb5fdf727a17ced5448158bbbf9c66 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 10 Jun 2016 09:46:07 +0200 Subject: [PATCH] Cleanup - Attempt --- src/Umbraco.Core/Attempt.cs | 186 +++++++----------- .../{AttemptOfT.cs => AttemptOfTResult.cs} | 44 ++--- src/Umbraco.Core/AttemptOfTResultTStatus.cs | 142 +++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 3 +- src/Umbraco.Tests/AttemptTests.cs | 30 --- .../Models/DynamicPublishedContent.cs | 2 +- src/Umbraco.Web/Models/Trees/MenuItem.cs | 72 ++++--- .../Trees/LegacyTreeDataConverter.cs | 38 ++-- 8 files changed, 303 insertions(+), 214 deletions(-) rename src/Umbraco.Core/{AttemptOfT.cs => AttemptOfTResult.cs} (68%) create mode 100644 src/Umbraco.Core/AttemptOfTResultTStatus.cs diff --git a/src/Umbraco.Core/Attempt.cs b/src/Umbraco.Core/Attempt.cs index ca2bbe35fe..b5c7430974 100644 --- a/src/Umbraco.Core/Attempt.cs +++ b/src/Umbraco.Core/Attempt.cs @@ -7,160 +7,110 @@ namespace Umbraco.Core /// public static class Attempt { + // note: + // cannot rely on overloads only to differenciate between with/without status + // in some cases it will always be ambiguous, so be explicit w/ 'WithStatus' methods + /// /// Creates a successful attempt with a result. /// - /// The type of the attempted operation result. + /// The type of the attempted operation result. /// The result of the attempt. /// The successful attempt. - public static Attempt Succeed(T result) + public static Attempt Succeed(TResult result) { - return Attempt.Succeed(result); + return Attempt.Succeed(result); + } + + /// + /// Creates a successful attempt with a result and a status. + /// + /// The type of the attempted operation result. + /// The type of the attempted operation status. + /// The status of the attempt. + /// The result of the attempt. + /// The successful attempt. + public static Attempt SucceedWithStatus(TStatus status, TResult result) + { + return Attempt.Succeed(status, result); } /// /// Creates a failed attempt with a result. /// - /// The type of the attempted operation result. + /// The type of the attempted operation result. /// The result of the attempt. /// The failed attempt. - public static Attempt Fail(T result) + public static Attempt Fail(TResult result) { - return Attempt.Fail(result); + return Attempt.Fail(result); + } + + /// + /// Creates a failed attempt with a result and a status. + /// + /// The type of the attempted operation result. + /// The type of the attempted operation status. + /// The status of the attempt. + /// The result of the attempt. + /// The failed attempt. + public static Attempt FailWithStatus(TStatus status, TResult result) + { + return Attempt.Fail(status, result); } /// /// Creates a failed attempt with a result and an exception. /// - /// The type of the attempted operation result. + /// 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) + public static Attempt Fail(TResult result, Exception exception) { - return Attempt.Fail(result, exception); + return Attempt.Fail(result, exception); + } + + + /// + /// Creates a failed attempt with a result, an exception and a status. + /// + /// The type of the attempted operation result. + /// The type of the attempted operation status. + /// The status of the attempt. + /// The result of the attempt. + /// The exception causing the failure of the attempt. + /// The failed attempt. + public static Attempt FailWithStatus(TStatus status, TResult result, Exception exception) + { + return Attempt.Fail(status, result, exception); } /// /// 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 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) + public static Attempt If(bool condition, TResult result) { - 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; + return Attempt.If(condition, result); } /// - /// Represents the outcome of an attempt. + /// Creates a successful or a failed attempt, with a result. /// - /// Can be a success or a failure, and allows for attempts chaining. - public struct Outcome + /// The type of the attempted operation result. + /// The type of the attempted operation status. + /// A value indicating whether the attempt is successful. + /// The status of the successful attempt. + /// The status of the failed attempt. + /// The result of the attempt. + /// The attempt. + public static Attempt IfWithStatus(bool condition, TStatus succStatus, TStatus failStatus, TResult result) { - 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; - } + return Attempt.If(condition, succStatus, failStatus, result); } - } } \ No newline at end of file diff --git a/src/Umbraco.Core/AttemptOfT.cs b/src/Umbraco.Core/AttemptOfTResult.cs similarity index 68% rename from src/Umbraco.Core/AttemptOfT.cs rename to src/Umbraco.Core/AttemptOfTResult.cs index d9e2abb186..81268e4e5a 100644 --- a/src/Umbraco.Core/AttemptOfT.cs +++ b/src/Umbraco.Core/AttemptOfTResult.cs @@ -5,12 +5,12 @@ namespace Umbraco.Core /// /// Represents the result of an operation attempt. /// - /// The type of the attempted operation result. + /// The type of the attempted operation result. [Serializable] - public struct Attempt + public struct Attempt { /// - /// Gets a value indicating whether this was successful. + /// Gets a value indicating whether this was successful. /// public bool Success { get; } @@ -22,13 +22,13 @@ namespace Umbraco.Core /// /// Gets the attempt result. /// - public T Result { get; } + public TResult Result { get; } // optimize, use a singleton failed attempt - private static readonly Attempt Failed = new Attempt(false, default(T), null); + private static readonly Attempt Failed = new Attempt(false, default(TResult), null); // private - use Succeed() or Fail() methods to create attempts - private Attempt(bool success, T result, Exception exception) + private Attempt(bool success, TResult result, Exception exception) { Success = success; Result = result; @@ -39,9 +39,9 @@ namespace Umbraco.Core /// Creates a successful attempt. /// /// The successful attempt. - public static Attempt Succeed() + public static Attempt Succeed() { - return new Attempt(true, default(T), null); + return new Attempt(true, default(TResult), null); } /// @@ -49,16 +49,16 @@ namespace Umbraco.Core /// /// The result of the attempt. /// The successful attempt. - public static Attempt Succeed(T result) + public static Attempt Succeed(TResult result) { - return new Attempt(true, result, null); + return new Attempt(true, result, null); } /// /// Creates a failed attempt. /// /// The failed attempt. - public static Attempt Fail() + public static Attempt Fail() { return Failed; } @@ -68,9 +68,9 @@ namespace Umbraco.Core /// /// The exception causing the failure of the attempt. /// The failed attempt. - public static Attempt Fail(Exception exception) + public static Attempt Fail(Exception exception) { - return new Attempt(false, default(T), exception); + return new Attempt(false, default(TResult), exception); } /// @@ -78,9 +78,9 @@ namespace Umbraco.Core /// /// The result of the attempt. /// The failed attempt. - public static Attempt Fail(T result) + public static Attempt Fail(TResult result) { - return new Attempt(false, result, null); + return new Attempt(false, result, null); } /// @@ -89,9 +89,9 @@ namespace Umbraco.Core /// The result of the attempt. /// The exception causing the failure of the attempt. /// The failed attempt. - public static Attempt Fail(T result, Exception exception) + public static Attempt Fail(TResult result, Exception exception) { - return new Attempt(false, result, exception); + return new Attempt(false, result, exception); } /// @@ -99,9 +99,9 @@ namespace Umbraco.Core /// /// A value indicating whether the attempt is successful. /// The attempt. - public static Attempt SucceedIf(bool condition) + public static Attempt If(bool condition) { - return condition ? new Attempt(true, default(T), null) : Failed; + return condition ? new Attempt(true, default(TResult), null) : Failed; } /// @@ -110,9 +110,9 @@ namespace Umbraco.Core /// A value indicating whether the attempt is successful. /// The result of the attempt. /// The attempt. - public static Attempt SucceedIf(bool condition, T result) + public static Attempt If(bool condition, TResult result) { - return new Attempt(condition, result, null); + return new Attempt(condition, result, null); } /// @@ -120,7 +120,7 @@ namespace Umbraco.Core /// /// /// - public static implicit operator bool(Attempt a) + public static implicit operator bool(Attempt a) { return a.Success; } diff --git a/src/Umbraco.Core/AttemptOfTResultTStatus.cs b/src/Umbraco.Core/AttemptOfTResultTStatus.cs new file mode 100644 index 0000000000..ca66b0a961 --- /dev/null +++ b/src/Umbraco.Core/AttemptOfTResultTStatus.cs @@ -0,0 +1,142 @@ +using System; + +namespace Umbraco.Core +{ + /// + /// Represents the result of an operation attempt. + /// + /// The type of the attempted operation result. + /// The type of the attempted operation status. + [Serializable] + public struct Attempt + { + /// + /// Gets a value indicating whether this was successful. + /// + public bool Success { get; } + + /// + /// Gets the exception associated with an unsuccessful attempt. + /// + public Exception Exception { get; } + + /// + /// Gets the attempt result. + /// + public TResult Result { get; } + + /// + /// Gets the attempt status. + /// + public TStatus Status { get; } + + // private - use Succeed() or Fail() methods to create attempts + private Attempt(bool success, TResult result, TStatus status, Exception exception) + { + Success = success; + Result = result; + Status = status; + Exception = exception; + } + + /// + /// Creates a successful attempt. + /// + /// The status of the attempt. + /// The successful attempt. + public static Attempt Succeed(TStatus status) + { + return new Attempt(true, default(TResult), status, null); + } + + /// + /// Creates a successful attempt with a result. + /// + /// The status of the attempt. + /// The result of the attempt. + /// The successful attempt. + public static Attempt Succeed(TStatus status, TResult result) + { + return new Attempt(true, result, status, null); + } + + /// + /// Creates a failed attempt. + /// + /// The status of the attempt. + /// The failed attempt. + public static Attempt Fail(TStatus status) + { + return new Attempt(false, default(TResult), status, null); + } + + /// + /// Creates a failed attempt with an exception. + /// + /// The status of the attempt. + /// The exception causing the failure of the attempt. + /// The failed attempt. + public static Attempt Fail(TStatus status, Exception exception) + { + return new Attempt(false, default(TResult), status, exception); + } + + /// + /// Creates a failed attempt with a result. + /// + /// The status of the attempt. + /// The result of the attempt. + /// The failed attempt. + public static Attempt Fail(TStatus status, TResult result) + { + return new Attempt(false, result, status, null); + } + + /// + /// Creates a failed attempt with a result and an exception. + /// + /// The status of the attempt. + /// The result of the attempt. + /// The exception causing the failure of the attempt. + /// The failed attempt. + public static Attempt Fail(TStatus status, TResult result, Exception exception) + { + return new Attempt(false, result, status, exception); + } + + /// + /// Creates a successful or a failed attempt. + /// + /// A value indicating whether the attempt is successful. + /// The status of the successful attempt. + /// The status of the failed attempt. + /// The attempt. + public static Attempt If(bool condition, TStatus succStatus, TStatus failStatus) + { + return new Attempt(condition, default(TResult), condition ? succStatus : failStatus, null); + } + + /// + /// Creates a successful or a failed attempt, with a result. + /// + /// A value indicating whether the attempt is successful. + /// The status of the successful attempt. + /// The status of the failed attempt. + /// The result of the attempt. + /// The attempt. + public static Attempt If(bool condition, TStatus succStatus, TStatus failStatus, TResult result) + { + return new Attempt(condition, result, condition ? succStatus : failStatus, null); + } + + /// + /// Implicity operator to check if the attempt was successful without having to access the 'success' property + /// + /// + /// + public static implicit operator bool(Attempt a) + { + return a.Success; + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 3ea3d79581..38f34e690d 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -69,7 +69,8 @@ - + + diff --git a/src/Umbraco.Tests/AttemptTests.cs b/src/Umbraco.Tests/AttemptTests.cs index a912fdf2a7..84d33c4351 100644 --- a/src/Umbraco.Tests/AttemptTests.cs +++ b/src/Umbraco.Tests/AttemptTests.cs @@ -7,36 +7,6 @@ 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.")); - } [Test] public void AttemptIf() diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index 2dd1e338ea..4e64ba3564 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -198,7 +198,7 @@ namespace Umbraco.Web.Models } var value = PublishedContent.GetPropertyValue(name, recurse); - return Attempt.SucceedIf(value != null, value); + return Attempt.If(value != null, value); } /// diff --git a/src/Umbraco.Web/Models/Trees/MenuItem.cs b/src/Umbraco.Web/Models/Trees/MenuItem.cs index e1a656857a..b25918fbf6 100644 --- a/src/Umbraco.Web/Models/Trees/MenuItem.cs +++ b/src/Umbraco.Web/Models/Trees/MenuItem.cs @@ -177,38 +177,54 @@ namespace Umbraco.Web.Models.Trees internal void ConvertLegacyMenuItem(IUmbracoEntity item, string nodeType, string currentSection) { - //First try to get a URL/title from the legacy action, - // if that doesn't work, try to get the legacy confirm view - - //in some edge cases, item can be null so we'll just convert those to "-1" and "" for id and name since these edge cases don't need that. - Attempt - .Try(LegacyTreeDataConverter.GetUrlAndTitleFromLegacyAction(Action, - item == null ? "-1" : item.Id.ToInvariantString(), - nodeType, - item == null ? "" : item.Name, currentSection), - action => LaunchDialogUrl(action.Url, action.DialogTitle)) - .OnFailure(() => LegacyTreeDataConverter.GetLegacyConfirmView(Action, currentSection), - view => LaunchDialogView( - view, - ApplicationContext.Current.Services.TextService.Localize("defaultdialogs/confirmdelete") + " '" + (item == null ? "" : item.Name) + "' ?")); + // try to get a URL/title from the legacy action, + // in some edge cases, item can be null so we'll just convert those to "-1" and "" for id and name since these edge cases don't need that. + var attempt = LegacyTreeDataConverter.GetUrlAndTitleFromLegacyAction(Action, + item == null ? "-1" : item.Id.ToInvariantString(), + nodeType, + item == null ? "" : item.Name, currentSection); + if (attempt) + { + var action = attempt.Result; + LaunchDialogUrl(action.Url, action.DialogTitle); + } + else + { + // if that doesn't work, try to get the legacy confirm view + var attempt2 = LegacyTreeDataConverter.GetLegacyConfirmView(Action, currentSection); + if (attempt2) + { + var view = attempt2.Result; + var textService = ApplicationContext.Current.Services.TextService; + LaunchDialogView(view, textService.Localize("defaultdialogs/confirmdelete") + " '" + (item == null ? "" : item.Name) + "' ?"); + } + } } internal void ConvertLegacyFileSystemMenuItem(string path, string nodeType, string currentSection) { - //First try to get a URL/title from the legacy action, - // if that doesn't work, try to get the legacy confirm view - - //in some edge cases, item can be null so we'll just convert those to "-1" and "" for id and name since these edge cases don't need that. - Attempt - .Try(LegacyTreeDataConverter.GetUrlAndTitleFromLegacyAction(Action, - path, - nodeType, - path, currentSection), - action => LaunchDialogUrl(action.Url, action.DialogTitle)) - .OnFailure(() => LegacyTreeDataConverter.GetLegacyConfirmView(Action, currentSection), - view => LaunchDialogView( - view, - ApplicationContext.Current.Services.TextService.Localize("defaultdialogs/confirmdelete") + " '" + path + "' ?")); + // try to get a URL/title from the legacy action, + // in some edge cases, item can be null so we'll just convert those to "-1" and "" for id and name since these edge cases don't need that. + var attempt = LegacyTreeDataConverter.GetUrlAndTitleFromLegacyAction(Action, + path, + nodeType, + path, currentSection); + if (attempt) + { + var action = attempt.Result; + LaunchDialogUrl(action.Url, action.DialogTitle); + } + else + { + // if that doesn't work, try to get the legacy confirm view + var attempt2 = LegacyTreeDataConverter.GetLegacyConfirmView(Action, currentSection); + if (attempt2) + { + var view = attempt2.Result; + var textService = ApplicationContext.Current.Services.TextService; + LaunchDialogView(view, textService.Localize("defaultdialogs/confirmdelete") + " '" + path + "' ?"); + } + } } #endregion diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs index 5204f02622..69a07811ad 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs @@ -127,20 +127,30 @@ namespace Umbraco.Web.Trees var currentAction = t; - //First try to get a URL/title from the legacy action, - // if that doesn't work, try to get the legacy confirm view - // if that doesn't work and there's no jsAction in there already then add the legacy js method call - Attempt - .Try(GetUrlAndTitleFromLegacyAction(currentAction, xmlTreeNode.NodeID, xmlTreeNode.NodeType, xmlTreeNode.Text, currentSection), - action => menuItem.LaunchDialogUrl(action.Url, action.DialogTitle)) - .OnFailure(() => GetLegacyConfirmView(currentAction, currentSection), - view => menuItem.LaunchDialogView( - view, - ApplicationContext.Current.Services.TextService.Localize("defaultdialogs/confirmdelete") + " '" + xmlTreeNode.Text + "' ?")) - .OnFailure(() => menuItem.AdditionalData.ContainsKey(MenuItem.JsActionKey) - ? Attempt.Fail(false) - : Attempt.Succeed(true), - b => menuItem.ExecuteLegacyJs(menuItem.Action.JsFunctionName)); + // try to get a URL/title from the legacy action + var attempt = GetUrlAndTitleFromLegacyAction(currentAction, xmlTreeNode.NodeID, xmlTreeNode.NodeType, xmlTreeNode.Text, currentSection); + if (attempt) + { + var action = attempt.Result; + menuItem.LaunchDialogUrl(action.Url, action.DialogTitle); + } + else + { + // if that doesn't work, try to get the legacy confirm view + var attempt2 = GetLegacyConfirmView(currentAction, currentSection); + if (attempt2) + { + var view = attempt2.Result; + var textService = ApplicationContext.Current.Services.TextService; + menuItem.LaunchDialogView(view, textService.Localize("defaultdialogs/confirmdelete") + " '" + xmlTreeNode.Text + "' ?"); + } + else + { + // if that doesn't work and there's no jsAction in there already then add the legacy js method call + if (menuItem.AdditionalData.ContainsKey(MenuItem.JsActionKey) == false) + menuItem.ExecuteLegacyJs(menuItem.Action.JsFunctionName); + } + } numAdded++; }