Resvolution - ActionResolver
This commit is contained in:
@@ -68,44 +68,6 @@ namespace Umbraco.Core.ObjectResolution
|
||||
// about using it for anything else. Also, while the backdoor is open, the resolution system is locked so nothing
|
||||
// can work properly => deadlocks. Therefore, open the backdoor, do resolution changes EXCLUSIVELY, and close the door!
|
||||
|
||||
/// <summary>
|
||||
/// Returns a disposable object that reprents dirty access to temporarily unfrozen resolution configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Should not be used.</para>
|
||||
/// <para>Should be used in a <c>using(Resolution.DirtyBackdoorToConfiguration) { ... }</c> mode.</para>
|
||||
/// <para>Because we just lift the frozen state, and we don't actually re-freeze, the <c>Frozen</c> event does not trigger.</para>
|
||||
/// </remarks>
|
||||
internal static IDisposable DirtyBackdoorToConfiguration
|
||||
{
|
||||
get { return new DirtyBackdoor(); }
|
||||
}
|
||||
|
||||
// keep the class here because it needs write-access to Resolution.IsFrozen
|
||||
private class DirtyBackdoor : IDisposable
|
||||
{
|
||||
|
||||
private readonly IDisposable _lock;
|
||||
private readonly bool _frozen;
|
||||
|
||||
public DirtyBackdoor()
|
||||
{
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Creating back door for resolution");
|
||||
|
||||
_lock = new WriteLock(ConfigurationLock);
|
||||
_frozen = _isFrozen;
|
||||
_isFrozen = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Disposing back door for resolution");
|
||||
|
||||
_isFrozen = _frozen;
|
||||
_lock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes resolution.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,184 +1,177 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Web.UI.Pages;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
|
||||
namespace Umbraco.Tests.Resolvers
|
||||
{
|
||||
[TestFixture]
|
||||
public class ActionsResolverTests : ResolverBaseTest
|
||||
{
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ActionsResolver.Reset();
|
||||
}
|
||||
|
||||
// NOTE
|
||||
// ManyResolverTests ensure that we'll get our actions back and ActionsResolver works,
|
||||
// so all we're testing here is that plugin manager _does_ find our actions
|
||||
// which should be ensured by PlugingManagerTests anyway, so this is useless?
|
||||
// maybe not as it seems to handle the "instance" thing... so we test that we respect the singleton?
|
||||
[Test]
|
||||
public void FindAllActions()
|
||||
{
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
new ActivatorServiceProvider(), ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveActions());
|
||||
|
||||
Resolution.Freeze();
|
||||
|
||||
var actions = ActionsResolver.Current.Actions;
|
||||
Assert.AreEqual(2, actions.Count());
|
||||
|
||||
// order is unspecified, but both must be there
|
||||
bool hasAction1 = actions.ElementAt(0) is SingletonAction || actions.ElementAt(1) is SingletonAction;
|
||||
bool hasAction2 = actions.ElementAt(0) is NonSingletonAction || actions.ElementAt(1) is NonSingletonAction;
|
||||
Assert.IsTrue(hasAction1);
|
||||
Assert.IsTrue(hasAction2);
|
||||
|
||||
SingletonAction action = (SingletonAction)(actions.ElementAt(0) is SingletonAction ? actions.ElementAt(0) : actions.ElementAt(1));
|
||||
|
||||
// ensure we respect the singleton
|
||||
Assert.AreSame(SingletonAction.Instance, action);
|
||||
}
|
||||
|
||||
#region Classes for tests
|
||||
|
||||
public class SingletonAction : IAction
|
||||
{
|
||||
//create singleton
|
||||
private static readonly SingletonAction instance = new SingletonAction();
|
||||
|
||||
public static SingletonAction Instance
|
||||
{
|
||||
get { return instance; }
|
||||
}
|
||||
|
||||
#region IAction Members
|
||||
|
||||
public char Letter
|
||||
{
|
||||
get
|
||||
{
|
||||
return 'I';
|
||||
}
|
||||
}
|
||||
|
||||
public string JsFunctionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
|
||||
}
|
||||
}
|
||||
|
||||
public string JsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get
|
||||
{
|
||||
return "assignDomain";
|
||||
}
|
||||
}
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
return ".sprDomain";
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowInNotifier
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool CanBePermissionAssigned
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class NonSingletonAction : IAction
|
||||
{
|
||||
#region IAction Members
|
||||
|
||||
public char Letter
|
||||
{
|
||||
get
|
||||
{
|
||||
return 'Q';
|
||||
}
|
||||
}
|
||||
|
||||
public string JsFunctionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
|
||||
}
|
||||
}
|
||||
|
||||
public string JsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get
|
||||
{
|
||||
return "asfasdf";
|
||||
}
|
||||
}
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
return ".sprDomain";
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowInNotifier
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool CanBePermissionAssigned
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Web.UI.Pages;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
|
||||
namespace Umbraco.Tests.Resolvers
|
||||
{
|
||||
[TestFixture]
|
||||
public class ActionCollectionTests : ResolverBaseTest
|
||||
{
|
||||
// NOTE
|
||||
// ManyResolverTests ensure that we'll get our actions back and ActionsResolver works,
|
||||
// so all we're testing here is that plugin manager _does_ find our actions
|
||||
// which should be ensured by PlugingManagerTests anyway, so this is useless?
|
||||
// maybe not as it seems to handle the "instance" thing... so we test that we respect the singleton?
|
||||
[Test]
|
||||
public void FindAllActions()
|
||||
{
|
||||
var collectionBuilder = new ActionCollectionBuilder();
|
||||
collectionBuilder.SetProducer(() => PluginManager.ResolveActions());
|
||||
|
||||
var actions = collectionBuilder.CreateCollection();
|
||||
Assert.AreEqual(2, actions.Count());
|
||||
|
||||
// order is unspecified, but both must be there
|
||||
var hasAction1 = actions.ElementAt(0) is SingletonAction || actions.ElementAt(1) is SingletonAction;
|
||||
var hasAction2 = actions.ElementAt(0) is NonSingletonAction || actions.ElementAt(1) is NonSingletonAction;
|
||||
Assert.IsTrue(hasAction1);
|
||||
Assert.IsTrue(hasAction2);
|
||||
|
||||
var action = (SingletonAction)(actions.ElementAt(0) is SingletonAction ? actions.ElementAt(0) : actions.ElementAt(1));
|
||||
|
||||
// ensure we respect the singleton
|
||||
Assert.AreSame(SingletonAction.Instance, action);
|
||||
}
|
||||
|
||||
#region Classes for tests
|
||||
|
||||
public class SingletonAction : IAction
|
||||
{
|
||||
//create singleton
|
||||
private static readonly SingletonAction instance = new SingletonAction();
|
||||
|
||||
public static SingletonAction Instance
|
||||
{
|
||||
get { return instance; }
|
||||
}
|
||||
|
||||
#region IAction Members
|
||||
|
||||
public char Letter
|
||||
{
|
||||
get
|
||||
{
|
||||
return 'I';
|
||||
}
|
||||
}
|
||||
|
||||
public string JsFunctionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
|
||||
}
|
||||
}
|
||||
|
||||
public string JsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get
|
||||
{
|
||||
return "assignDomain";
|
||||
}
|
||||
}
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
return ".sprDomain";
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowInNotifier
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool CanBePermissionAssigned
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class NonSingletonAction : IAction
|
||||
{
|
||||
#region IAction Members
|
||||
|
||||
public char Letter
|
||||
{
|
||||
get
|
||||
{
|
||||
return 'Q';
|
||||
}
|
||||
}
|
||||
|
||||
public string JsFunctionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
|
||||
}
|
||||
}
|
||||
|
||||
public string JsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get
|
||||
{
|
||||
return "asfasdf";
|
||||
}
|
||||
}
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
return ".sprDomain";
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowInNotifier
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool CanBePermissionAssigned
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,6 @@ namespace Umbraco.Tests.Resolvers
|
||||
[TestFixture]
|
||||
public class XsltExtensionsResolverTests : ResolverBaseTest
|
||||
{
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ActionsResolver.Reset();
|
||||
}
|
||||
|
||||
// NOTE
|
||||
// ManyResolverTests ensure that we'll get our actions back and ActionsResolver works,
|
||||
// so all we're testing here is that plugin manager _does_ find our actions
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
<Compile Include="Persistence\Repositories\StylesheetRepositoryTest.cs" />
|
||||
<Compile Include="PublishedContent\PublishedContentMoreTests.cs" />
|
||||
<Compile Include="Publishing\PublishingStrategyTests.cs" />
|
||||
<Compile Include="Resolvers\ActionsResolverTests.cs" />
|
||||
<Compile Include="Resolvers\ActionCollectionTests.cs" />
|
||||
<Compile Include="Logging\RingBufferTest.cs" />
|
||||
<Compile Include="TestHelpers\BaseUmbracoConfigurationTest.cs" />
|
||||
<Compile Include="TestHelpers\DatabaseTestBehaviorAttribute.cs" />
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core.Strings;
|
||||
using Umbraco.Web.HealthCheck;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
using CoreCurrent = Umbraco.Core.DependencyInjection.Current;
|
||||
|
||||
namespace Umbraco.Web
|
||||
@@ -118,6 +119,12 @@ namespace Umbraco.Web
|
||||
public static HealthCheckCollectionBuilder HealthCheckCollectionBuilder
|
||||
=> Container.GetInstance<HealthCheckCollectionBuilder>();
|
||||
|
||||
public static ActionCollectionBuilder ActionCollectionBuilder
|
||||
=> Container.GetInstance<ActionCollectionBuilder>();
|
||||
|
||||
public static ActionCollection Actions
|
||||
=> Container.GetInstance<ActionCollection>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Core Getters
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Umbraco.Web.Models.Trees
|
||||
internal MenuItem CreateMenuItem<T>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
|
||||
where T : IAction
|
||||
{
|
||||
var item = ActionsResolver.Current.GetAction<T>();
|
||||
var item = Current.Actions.GetAction<T>();
|
||||
if (item != null)
|
||||
{
|
||||
var menuItem = new MenuItem(item, name)
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Umbraco.Web.Trees
|
||||
//We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered
|
||||
// this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here.
|
||||
[UmbracoApplicationAuthorize(
|
||||
Constants.Applications.Content,
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Content,
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Users,
|
||||
Constants.Applications.Settings,
|
||||
Constants.Applications.Developer,
|
||||
@@ -29,10 +29,10 @@ namespace Umbraco.Web.Trees
|
||||
[CoreTree]
|
||||
public class ContentTreeController : ContentTreeControllerBase
|
||||
{
|
||||
|
||||
|
||||
protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
|
||||
{
|
||||
var node = base.CreateRootNode(queryStrings);
|
||||
var node = base.CreateRootNode(queryStrings);
|
||||
//if the user's start node is not default, then ensure the root doesn't have a menu
|
||||
if (Security.CurrentUser.StartContentId != Constants.System.Root)
|
||||
{
|
||||
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Trees
|
||||
{
|
||||
get { return Security.CurrentUser.StartContentId; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a tree node for a content item based on an UmbracoEntity
|
||||
/// </summary>
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Web.Trees
|
||||
node.AdditionalData.Add("isContainer", true);
|
||||
node.SetContainerStyle();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (entity.IsPublished == false)
|
||||
node.SetNotPublishedStyle();
|
||||
@@ -142,7 +142,7 @@ namespace Umbraco.Web.Trees
|
||||
// add default actions for *all* users
|
||||
menu.Items.Add<ActionRePublish>(Services.TextService.Localize("actions", ActionRePublish.Instance.Alias)).ConvertLegacyMenuItem(null, "content", "content");
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
|
||||
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace Umbraco.Web.Trees
|
||||
|
||||
var nodeMenu = GetAllNodeMenuItems(item);
|
||||
var allowedMenuItems = GetAllowedUserMenuItemsForNode(item);
|
||||
|
||||
|
||||
FilterUserAllowedMenuItems(nodeMenu, allowedMenuItems);
|
||||
|
||||
//if the media item is in the recycle bin, don't have a default menu, just show the regular menu
|
||||
@@ -173,9 +173,9 @@ namespace Umbraco.Web.Trees
|
||||
else
|
||||
{
|
||||
//set the default to create
|
||||
nodeMenu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
nodeMenu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return nodeMenu;
|
||||
}
|
||||
@@ -209,31 +209,45 @@ namespace Umbraco.Web.Trees
|
||||
protected MenuItemCollection GetAllNodeMenuItems(IUmbracoEntity item)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
|
||||
|
||||
AddActionNode<ActionNew>(item, menu);
|
||||
AddActionNode<ActionDelete>(item, menu);
|
||||
|
||||
//need to ensure some of these are converted to the legacy system - until we upgrade them all to be angularized.
|
||||
menu.Items.Add<ActionMove>(Services.TextService.Localize("actions", ActionMove.Instance.Alias), true);
|
||||
menu.Items.Add<ActionCopy>(Services.TextService.Localize("actions", ActionCopy.Instance.Alias));
|
||||
menu.Items.Add<ActionChangeDocType>(Services.TextService.Localize("actions", ActionChangeDocType.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
AddActionNode<ActionMove>(item, menu, true);
|
||||
AddActionNode<ActionCopy>(item, menu);
|
||||
AddActionNode<ActionChangeDocType>(item, menu, convert: true);
|
||||
|
||||
menu.Items.Add<ActionSort>(Services.TextService.Localize("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
|
||||
AddActionNode<ActionSort>(item, menu, true, true);
|
||||
|
||||
menu.Items.Add<ActionRollback>(Services.TextService.Localize("actions", ActionRollback.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionAudit>(Services.TextService.Localize("actions", ActionAudit.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionPublish>(Services.TextService.Localize("actions", ActionPublish.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionToPublish>(Services.TextService.Localize("actions", ActionToPublish.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionAssignDomain>(Services.TextService.Localize("actions", ActionAssignDomain.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionRights>(Services.TextService.Localize("actions", ActionRights.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionProtect>(Services.TextService.Localize("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
|
||||
|
||||
menu.Items.Add<ActionNotify>(Services.TextService.Localize("actions", ActionNotify.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
|
||||
menu.Items.Add<ActionSendToTranslate>(Services.TextService.Localize("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
|
||||
AddActionNode<ActionRollback>(item, menu, convert: true);
|
||||
AddActionNode<ActionAudit>(item, menu, convert: true);
|
||||
AddActionNode<ActionPublish>(item, menu, true, true);
|
||||
AddActionNode<ActionToPublish>(item, menu, convert: true);
|
||||
AddActionNode<ActionAssignDomain>(item, menu, convert: true);
|
||||
AddActionNode<ActionRights>(item, menu, convert: true);
|
||||
AddActionNode<ActionProtect>(item, menu, true, true);
|
||||
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
|
||||
AddActionNode<ActionNotify>(item, menu, true, true);
|
||||
AddActionNode<ActionSendToTranslate>(item, menu, convert: true);
|
||||
|
||||
AddActionNode<RefreshNode, ActionRefresh>(item, menu, true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private void AddActionNode<TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false)
|
||||
where TAction : IAction
|
||||
{
|
||||
var menuItem = menu.Items.Add<TAction>(Services.TextService.Localize("actions", Current.Actions.GetAction<TAction>().Alias), hasSeparator);
|
||||
if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content");
|
||||
}
|
||||
|
||||
private void AddActionNode<TItem, TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false)
|
||||
where TItem : MenuItem, new()
|
||||
where TAction : IAction
|
||||
{
|
||||
var menuItem = menu.Items.Add<TItem, TAction>(Services.TextService.Localize("actions", Current.Actions.GetAction<TAction>().Alias), hasSeparator);
|
||||
if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ namespace Umbraco.Web.Trees
|
||||
public static string GetLegacyIActionJavascript()
|
||||
{
|
||||
var js = new StringBuilder();
|
||||
foreach (var a in ActionsResolver.Current.Actions.ToList())
|
||||
foreach (var a in Current.Actions)
|
||||
{
|
||||
// NH: Added a try/catch block to this as an error in a 3rd party action can crash the whole menu initialization
|
||||
try
|
||||
|
||||
@@ -476,9 +476,8 @@ namespace Umbraco.Web
|
||||
}));
|
||||
}
|
||||
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveActions());
|
||||
ActionCollectionBuilder.Register(Container)
|
||||
.SetProducer(() => PluginManager.ResolveActions());
|
||||
|
||||
SurfaceControllerResolver.Current = new SurfaceControllerResolver(
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
///
|
||||
/// The Action class itself has responsibility for registering actions and actionhandlers,
|
||||
/// and contains methods which will be invoked whenever a change is made to ex. a document, media or member
|
||||
///
|
||||
/// An action/actionhandler will automatically be registered, using reflection
|
||||
///
|
||||
/// An action/actionhandler will automatically be registered, using reflection
|
||||
/// which is enabling thirdparty developers to extend the core functionality of
|
||||
/// umbraco without changing the codebase.
|
||||
/// </summary>
|
||||
@@ -47,20 +47,8 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
// NOTE use the DirtyBackdoor to change the resolution configuration EXCLUSIVELY
|
||||
// ie do NOT do ANYTHING else while holding the backdoor, because while it is open
|
||||
// the whole resolution system is locked => nothing can work properly => deadlocks
|
||||
|
||||
var newResolver = new ActionsResolver(
|
||||
new ActivatorServiceProvider(), LoggerResolver.Current.Logger,
|
||||
() => TypeFinder.FindClassesOfType<IAction>(PluginManager.Current.AssembliesToScan));
|
||||
|
||||
using (Umbraco.Core.ObjectResolution.Resolution.DirtyBackdoorToConfiguration)
|
||||
{
|
||||
ActionsResolver.Reset(false); // and do NOT reset the whole resolution!
|
||||
ActionsResolver.Current = newResolver;
|
||||
}
|
||||
|
||||
// this will reset the collection
|
||||
Current.ActionCollectionBuilder.SetProducer(() => TypeFinder.FindClassesOfType<IAction>(PluginManager.Current.AssembliesToScan));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +69,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
/// <returns></returns>
|
||||
public static List<string> GetJavaScriptFileReferences()
|
||||
{
|
||||
return ActionsResolver.Current.Actions
|
||||
return Current.Actions
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.JsSource))
|
||||
.Select(x => x.JsSource).ToList();
|
||||
//return ActionJsReference;
|
||||
@@ -90,7 +78,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
/// <summary>
|
||||
/// Javascript menuitems - tree contextmenu
|
||||
/// Umbraco console
|
||||
///
|
||||
///
|
||||
/// Suggestion: this method should be moved to the presentation layer.
|
||||
/// </summary>
|
||||
/// <param name="language"></param>
|
||||
@@ -101,7 +89,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
{
|
||||
string _actionJsList = "";
|
||||
|
||||
foreach (IAction action in ActionsResolver.Current.Actions)
|
||||
foreach (IAction action in Current.Actions)
|
||||
{
|
||||
// Adding try/catch so this rutine doesn't fail if one of the actions fail
|
||||
// Add to language JsList
|
||||
@@ -139,7 +127,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
List<IAction> list = new List<IAction>();
|
||||
foreach (var c in entityPermission.AssignedPermissions.Where(x => x.Length == 1).Select(x => x.ToCharArray()[0]))
|
||||
{
|
||||
IAction action = ActionsResolver.Current.Actions.ToList().Find(
|
||||
IAction action = Current.Actions.ToList().Find(
|
||||
delegate (IAction a)
|
||||
{
|
||||
return a.Letter == c;
|
||||
@@ -162,7 +150,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
List<IAction> list = new List<IAction>();
|
||||
foreach (char c in actions.ToCharArray())
|
||||
{
|
||||
IAction action = ActionsResolver.Current.Actions.ToList().Find(
|
||||
IAction action = Current.Actions.ToList().Find(
|
||||
delegate(IAction a)
|
||||
{
|
||||
return a.Letter == c;
|
||||
@@ -190,7 +178,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
/// <returns></returns>
|
||||
public static List<IAction> GetPermissionAssignable()
|
||||
{
|
||||
return ActionsResolver.Current.Actions.ToList().FindAll(
|
||||
return Current.Actions.ToList().FindAll(
|
||||
delegate(IAction a)
|
||||
{
|
||||
return (a.CanBePermissionAssigned);
|
||||
|
||||
@@ -2,74 +2,83 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core._Legacy.PackageActions;
|
||||
using LightInject;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Web.UI.Pages;
|
||||
|
||||
namespace Umbraco.Web._Legacy.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to return all IAction objects
|
||||
/// </summary>
|
||||
public sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
public class ActionCollectionBuilder : ICollectionBuilder<ActionCollection, IAction>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> packageActions)
|
||||
: base(serviceProvider, logger, packageActions)
|
||||
{
|
||||
private static Func<IEnumerable<Type>> _producer;
|
||||
|
||||
public static ActionCollectionBuilder Register(IServiceContainer container)
|
||||
{
|
||||
// register the builder - per container
|
||||
var builderLifetime = new PerContainerLifetime();
|
||||
container.Register<ActionCollectionBuilder>(builderLifetime);
|
||||
|
||||
// get the builder, get the collection lifetime
|
||||
var builder = container.GetInstance<ActionCollectionBuilder>();
|
||||
var collectionLifetime = builder.CollectionLifetime;
|
||||
|
||||
// register the collection - special lifetime
|
||||
container.Register(factory => factory.GetInstance<ActionCollectionBuilder>().CreateCollection(), collectionLifetime);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IPackageAction"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<IAction> Actions
|
||||
{
|
||||
get
|
||||
{
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an Action if it exists.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
internal IAction GetAction<T>()
|
||||
where T : IAction
|
||||
{
|
||||
return Actions.SingleOrDefault(x => x.GetType() == typeof(T));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IAction> CreateInstances()
|
||||
public ActionCollection CreateCollection()
|
||||
{
|
||||
var actions = new List<IAction>();
|
||||
var foundIActions = InstanceTypes;
|
||||
foreach (var type in foundIActions)
|
||||
foreach (var type in _producer())
|
||||
{
|
||||
IAction typeInstance;
|
||||
var instance = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
|
||||
//if the singletone initializer is not found, try simply creating an instance of the IAction if it supports public constructors
|
||||
if (instance == null)
|
||||
typeInstance = ServiceProvider.GetService(type) as IAction;
|
||||
else
|
||||
typeInstance = instance.GetValue(null, null) as IAction;
|
||||
|
||||
if (typeInstance != null)
|
||||
{
|
||||
actions.Add(typeInstance);
|
||||
}
|
||||
var getter = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
|
||||
var instance = getter == null
|
||||
? Activator.CreateInstance(type) as IAction
|
||||
: getter.GetValue(null, null) as IAction;
|
||||
if (instance == null) continue;
|
||||
actions.Add(instance);
|
||||
}
|
||||
return actions;
|
||||
return new ActionCollection(actions);
|
||||
}
|
||||
|
||||
public void SetProducer(Func<IEnumerable<Type>> producer)
|
||||
{
|
||||
_producer = producer;
|
||||
CollectionLifetime.Reset();
|
||||
}
|
||||
|
||||
private ResettablePerContainerLifetime CollectionLifetime { get; } = new ResettablePerContainerLifetime();
|
||||
|
||||
private class ResettablePerContainerLifetime : ILifetime
|
||||
{
|
||||
private object _instance;
|
||||
|
||||
public object GetInstance(Func<object> createInstance, Scope scope)
|
||||
{
|
||||
// not dealing with disposable instances, actions are not disposable
|
||||
return _instance ?? (_instance = createInstance());
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionCollection : BuilderCollectionBase<IAction>
|
||||
{
|
||||
public ActionCollection(IEnumerable<IAction> items)
|
||||
: base(items)
|
||||
{ }
|
||||
|
||||
internal T GetAction<T>()
|
||||
where T : IAction
|
||||
{
|
||||
return this.OfType<T>().SingleOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAction
|
||||
@@ -91,11 +100,6 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
/// </summary>
|
||||
public class ActionAssignDomain : IAction
|
||||
{
|
||||
//create singleton
|
||||
#pragma warning disable 612,618
|
||||
private static readonly ActionAssignDomain m_instance = new ActionAssignDomain();
|
||||
#pragma warning restore 612,618
|
||||
|
||||
/// <summary>
|
||||
/// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons.
|
||||
/// All Umbraco assemblies should use the singleton instantiation (this.Instance)
|
||||
@@ -104,12 +108,9 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
[Obsolete("Use the singleton instantiation instead of a constructor")]
|
||||
public ActionAssignDomain() { }
|
||||
|
||||
public static ActionAssignDomain Instance
|
||||
{
|
||||
get { return m_instance; }
|
||||
}
|
||||
public static ActionAssignDomain Instance { get; } = new ActionAssignDomain();
|
||||
|
||||
#region IAction Members
|
||||
#region IAction Members
|
||||
|
||||
public char Letter
|
||||
{
|
||||
|
||||
@@ -8,11 +8,6 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
/// </summary>
|
||||
public class ActionAudit : IAction
|
||||
{
|
||||
//create singleton
|
||||
#pragma warning disable 612,618
|
||||
private static readonly ActionAudit m_instance = new ActionAudit();
|
||||
#pragma warning restore 612,618
|
||||
|
||||
/// <summary>
|
||||
/// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons.
|
||||
/// All Umbraco assemblies should use the singleton instantiation (this.Instance)
|
||||
@@ -21,10 +16,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
[Obsolete("Use the singleton instantiation instead of a constructor")]
|
||||
public ActionAudit() { }
|
||||
|
||||
public static ActionAudit Instance
|
||||
{
|
||||
get { return m_instance; }
|
||||
}
|
||||
public static ActionAudit Instance { get; } = new ActionAudit();
|
||||
|
||||
#region IAction Members
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
/// </summary>
|
||||
public class ActionNew : IAction
|
||||
{
|
||||
//create singleton
|
||||
private static readonly ActionNew InnerInstance = new ActionNew();
|
||||
|
||||
/// <summary>
|
||||
/// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons.
|
||||
/// All Umbraco assemblies should use the singleton instantiation (this.Instance)
|
||||
@@ -19,10 +16,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
[Obsolete("Use the singleton instantiation instead of a constructor")]
|
||||
public ActionNew() { }
|
||||
|
||||
public static ActionNew Instance
|
||||
{
|
||||
get { return InnerInstance; }
|
||||
}
|
||||
public static ActionNew Instance { get; } = new ActionNew();
|
||||
|
||||
#region IAction Members
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Web.Script.Serialization;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
using Action = Umbraco.Web._Legacy.Actions.Action;
|
||||
|
||||
@@ -21,7 +22,7 @@ namespace umbraco.controls.Tree
|
||||
});
|
||||
|
||||
List<IAction> allActions = new List<IAction>();
|
||||
foreach (var a in ActionsResolver.Current.Actions)
|
||||
foreach (var a in Current.Actions)
|
||||
{
|
||||
// NH: Added a try/catch block to this as an error in a 3rd party action can crash the whole menu initialization
|
||||
try
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Web.Script.Serialization;
|
||||
using System.Text;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
|
||||
namespace umbraco.controls.Tree
|
||||
@@ -67,7 +68,7 @@ namespace umbraco.controls.Tree
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
foreach (var a in ActionsResolver.Current.Actions)
|
||||
foreach (var a in Current.Actions)
|
||||
{
|
||||
types.Add(a.GetType());
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace umbraco.dialogs
|
||||
corner.Style.Add("border", "none");
|
||||
names.Cells.Add(corner);
|
||||
|
||||
foreach (var a in ActionsResolver.Current.Actions)
|
||||
foreach (var a in Current.Actions)
|
||||
{
|
||||
if (a.CanBePermissionAssigned == false) continue;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace umbraco.dialogs
|
||||
hc.Style.Add("border", "none");
|
||||
names.Cells.Add(hc);
|
||||
|
||||
foreach (var a in ActionsResolver.Current.Actions)
|
||||
foreach (var a in Current.Actions)
|
||||
{
|
||||
var chk = new CheckBox
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace umbraco.dialogs
|
||||
|
||||
node = Services.EntityService.Get(int.Parse(Request.GetItemAsString("id")));
|
||||
|
||||
var actionList = ActionsResolver.Current.Actions;
|
||||
var actionList = Current.Actions;
|
||||
|
||||
foreach (var a in actionList)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Web.UI.WebControls;
|
||||
using System.Web.UI.HtmlControls;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
using Action = Umbraco.Web._Legacy.Actions.Action;
|
||||
|
||||
@@ -41,7 +42,7 @@ namespace umbraco.presentation.umbraco.dialogs
|
||||
action = action.ToLower();
|
||||
if (action == "new")
|
||||
action = "create";
|
||||
var actions = ActionsResolver.Current.Actions;
|
||||
var actions = Current.Actions;
|
||||
foreach (var a in actions)
|
||||
{
|
||||
return Services.TextService.Localize(action);
|
||||
|
||||
Reference in New Issue
Block a user