From 3aaa1d84236b16c4b3b19a9007a128bcc1cafe08 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 22 Feb 2021 16:46:44 +0800 Subject: [PATCH 1/3] Add RequiredPermissionName to ApplicationMenuItem. --- .../Abp/Ui/Navigation/ApplicationMenuItem.cs | 7 ++- .../Volo/Abp/Ui/Navigation/MenuManager.cs | 54 ++++++++++++++++- .../Volo.Abp.UI.Navigation.Tests.csproj | 2 + .../Navigation/AbpUiNavigationTestModule.cs | 21 +++++++ .../Abp/Ui/Navigation/FakePermissionStore.cs | 28 +++++++++ .../Abp/Ui/Navigation/MenuManager_Tests.cs | 60 +++++++++++-------- .../TestPermissionDefinitionProvider.cs | 24 ++++++++ 7 files changed, 167 insertions(+), 29 deletions(-) create mode 100644 framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs create mode 100644 framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs create mode 100644 framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index 1c41727f7b..c1e4896513 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -71,6 +71,9 @@ namespace Volo.Abp.UI.Navigation [NotNull] public ApplicationMenuItemList Items { get; } + [CanBeNull] + public string RequiredPermissionName { get; } + /// /// Can be used to store a custom object related to this menu item. Optional. /// @@ -95,7 +98,8 @@ namespace Volo.Abp.UI.Navigation object customData = null, string target = null, string elementId = null, - string cssClass = null) + string cssClass = null, + string requiredPermissionName = null) { Check.NotNullOrWhiteSpace(name, nameof(name)); Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); @@ -109,6 +113,7 @@ namespace Volo.Abp.UI.Navigation Target = target; ElementId = elementId ?? GetDefaultElementId(); CssClass = cssClass; + RequiredPermissionName = requiredPermissionName; Items = new ApplicationMenuItemList(); } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index 5c33866aa2..6fe6102622 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; namespace Volo.Abp.UI.Navigation @@ -13,7 +15,7 @@ namespace Volo.Abp.UI.Navigation protected IHybridServiceScopeFactory ServiceScopeFactory { get; } public MenuManager( - IOptions options, + IOptions options, IHybridServiceScopeFactory serviceScopeFactory) { ServiceScopeFactory = serviceScopeFactory; @@ -32,6 +34,8 @@ namespace Volo.Abp.UI.Navigation { await contributor.ConfigureMenuAsync(context); } + + await CheckPermissionsAsync(scope.ServiceProvider, menu); } NormalizeMenu(menu); @@ -39,6 +43,52 @@ namespace Volo.Abp.UI.Navigation return menu; } + protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, IHasMenuItems menuWithItems) + { + var requiredPermissionMenus = new List(); + GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionMenus); + + if (requiredPermissionMenus.Any()) + { + var permissionChecker = serviceProvider.GetRequiredService(); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionMenus.Select(x => x.RequiredPermissionName).ToArray()); + + var toBeDeletedMenus = new List(); + foreach (var menu in requiredPermissionMenus) + { + if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted) + { + toBeDeletedMenus.Add(menu); + } + } + + RemoveMenus(menuWithItems, toBeDeletedMenus); + } + } + + protected virtual void GetRequiredPermissionNameMenus(IHasMenuItems menuWithItems, List output) + { + foreach (var menuItem in menuWithItems.Items) + { + if (!menuItem.RequiredPermissionName.IsNullOrWhiteSpace()) + { + output.Add(menuItem); + } + + GetRequiredPermissionNameMenus(menuItem, output); + } + } + + protected virtual void RemoveMenus(IHasMenuItems menuWithItems, List toBeDeleted) + { + menuWithItems.Items.RemoveAll(toBeDeleted.Contains); + + foreach (var menuItem in menuWithItems.Items) + { + RemoveMenus(menuItem, toBeDeleted); + } + } + protected virtual void NormalizeMenu(IHasMenuItems menuWithItems) { foreach (var menuItem in menuWithItems.Items) @@ -49,4 +99,4 @@ namespace Volo.Abp.UI.Navigation menuWithItems.Items.Normalize(); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj index ecfd73c615..a59bb11e0f 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj @@ -9,6 +9,8 @@ + + diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs new file mode 100644 index 0000000000..35b368cc1b --- /dev/null +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs @@ -0,0 +1,21 @@ +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace Volo.Abp.UI.Navigation +{ + [DependsOn(typeof(AbpUiNavigationModule))] + [DependsOn(typeof(AbpAuthorizationModule))] + [DependsOn(typeof(AbpAutofacModule))] + public class AbpUiNavigationTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor1()); + options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor2()); + }); + } + } +} diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs new file mode 100644 index 0000000000..ac074220f5 --- /dev/null +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.UI.Navigation +{ + public class FakePermissionStore : IPermissionStore, ITransientDependency + { + public Task IsGrantedAsync(string name, string providerName, string providerKey) + { + var result = (name.Contains("Administration") || name.Contains("Dashboard")) && !name.Contains("SubMenu1"); + return Task.FromResult(result); + } + + public Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in names) + { + result.Result.Add(name, (name.Contains("Administration") || name.Contains("Dashboard")) && !name.Contains("SubMenu1") + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited); + } + + return Task.FromResult(result); + } + } +} diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs index 96db1622b5..c72082945b 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs @@ -1,13 +1,17 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using NSubstitute; using Shouldly; -using Volo.Abp.Modularity; +using Volo.Abp.Security.Claims; using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.UI.Navigation { - public class MenuManager_Tests : AbpIntegratedTest + public class MenuManager_Tests : AbpIntegratedTest { private readonly IMenuManager _menuManager; @@ -16,6 +20,24 @@ namespace Volo.Abp.UI.Navigation _menuManager = ServiceProvider.GetRequiredService(); } + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + var claims = new List() { + new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"), + }; + + var identity = new ClaimsIdentity(claims); + var claimsPrincipal = new ClaimsPrincipal(identity); + var principalAccessor = Substitute.For(); + principalAccessor.Principal.Returns(ci => claimsPrincipal); + Thread.CurrentPrincipal = claimsPrincipal; + } + [Fact] public async Task Should_Get_Menu() { @@ -29,22 +51,8 @@ namespace Volo.Abp.UI.Navigation mainMenu.Items[1].Items[0].Name.ShouldBe("Administration.UserManagement"); mainMenu.Items[1].Items[1].Name.ShouldBe("Administration.RoleManagement"); mainMenu.Items[1].Items[2].Name.ShouldBe("Administration.DashboardSettings"); - mainMenu.Items[1].Items[3].Name.ShouldBe("Administration.SubMenu1"); - mainMenu.Items[1].Items[3].Items[0].Name.ShouldBe("Administration.SubMenu1.1"); - mainMenu.Items[1].Items[3].Items[1].Name.ShouldBe("Administration.SubMenu1.2"); - } - - [DependsOn(typeof(AbpUiNavigationModule))] - public class TestModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - Configure(options => - { - options.MenuContributors.Add(new TestMenuContributor1()); - options.MenuContributors.Add(new TestMenuContributor2()); - }); - } + mainMenu.Items[1].Items[3].Name.ShouldBe("Administration.SubMenu1"); //No need permission. + // Administration.SubMenu1.1 and Administration.SubMenu1.2 are removed because of don't have permissions. } /* Adds menu items: @@ -65,8 +73,8 @@ namespace Volo.Abp.UI.Navigation var administration = context.Menu.GetAdministration(); - administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users")); - administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles")); + administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users", requiredPermissionName: "Administration.UserManagement")); + administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles", requiredPermissionName: "Administration.RoleManagement")); return Task.CompletedTask; } @@ -86,16 +94,16 @@ namespace Volo.Abp.UI.Navigation return Task.CompletedTask; } - context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard")); + context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard", requiredPermissionName: "Dashboard")); var administration = context.Menu.GetAdministration(); - administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard")); + administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard", requiredPermissionName: "Administration.DashboardSettings")); administration.AddItem( - new ApplicationMenuItem("Administration.SubMenu1", "Sub menu 1") - .AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1")) - .AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2")) + new ApplicationMenuItem("Administration.SubMenu1", "Sub menu 1", url: "/submenu1") + .AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1", requiredPermissionName: "Administration.SubMenu1.1")) + .AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2", requiredPermissionName: "Administration.SubMenu1.2")) ); return Task.CompletedTask; diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..c9afe5a1f0 --- /dev/null +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs @@ -0,0 +1,24 @@ +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.UI.Navigation +{ + public class TestPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup("TestGroup"); + + group.AddPermission("Dashboard"); + + group.AddPermission("Administration"); + group.AddPermission("Administration.UserManagement"); + group.AddPermission("Administration.RoleManagement"); + + group.AddPermission("Administration.DashboardSettings"); + + group.AddPermission("Administration.SubMenu1"); + group.AddPermission("Administration.SubMenu1.1"); + group.AddPermission("Administration.SubMenu1.2"); + } + } +} From 0c65fec5610f6d2694dd0e5b4a95ed956a17b375 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 22 Feb 2021 22:13:04 +0800 Subject: [PATCH 2/3] Add RequiredPermissionName to ToolbarItem. --- .../Toolbars/ToolbarItem.cs | 8 +- .../Toolbars/ToolbarManager.cs | 31 ++++- .../Abp/Ui/Navigation/ApplicationMenuItem.cs | 2 +- .../Volo/Abp/Ui/Navigation/MenuManager.cs | 32 ++--- .../Shared/Permissions/FakePermissionStore.cs | 28 ++++ .../TestPermissionDefinitionProvider.cs | 16 +++ .../UI/Theme/Shared/Toolbars/Toolbar_Tests.cs | 129 ++++++++++++++++++ 7 files changed, 225 insertions(+), 21 deletions(-) create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs index 9b6ef4becb..4676202c24 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs @@ -14,10 +14,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars public int Order { get; set; } - public ToolbarItem([NotNull] Type componentType, int order = 0) + [CanBeNull] + public string RequiredPermissionName { get; set; } + + public ToolbarItem([NotNull] Type componentType, int order = 0, string requiredPermissionName = null) { Order = order; ComponentType = Check.NotNull(componentType, nameof(componentType)); + RequiredPermissionName = requiredPermissionName; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs index f1ac30779a..1f48b2825b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars @@ -14,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars protected IServiceProvider ServiceProvider { get; } public ToolbarManager( - IOptions options, + IOptions options, IServiceProvider serviceProvider, IThemeManager themeManager) { @@ -35,9 +38,33 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars { await contributor.ConfigureToolbarAsync(context); } + + await CheckPermissionsAsync(scope.ServiceProvider, toolbar); } return toolbar; } + + protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, Toolbar toolbar) + { + var requiredPermissionItems = toolbar.Items.Where(x => !x.RequiredPermissionName.IsNullOrWhiteSpace()).ToList(); + + if (requiredPermissionItems.Any()) + { + var permissionChecker = serviceProvider.GetRequiredService(); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray()); + + var toBeDeleted = new List(); + foreach (var item in requiredPermissionItems) + { + if (grantResult.Result[item.RequiredPermissionName!] != PermissionGrantResult.Granted) + { + toBeDeleted.Add(item); + } + } + + toolbar.Items.RemoveAll(toBeDeleted.Contains); + } + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index c1e4896513..63f4d7239d 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -72,7 +72,7 @@ namespace Volo.Abp.UI.Navigation public ApplicationMenuItemList Items { get; } [CanBeNull] - public string RequiredPermissionName { get; } + public string RequiredPermissionName { get; set; } /// /// Can be used to store a custom object related to this menu item. Optional. diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index 6fe6102622..d1f3ee330a 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -45,37 +45,37 @@ namespace Volo.Abp.UI.Navigation protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, IHasMenuItems menuWithItems) { - var requiredPermissionMenus = new List(); - GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionMenus); + var requiredPermissionItems = new List(); + GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionItems); - if (requiredPermissionMenus.Any()) + if (requiredPermissionItems.Any()) { var permissionChecker = serviceProvider.GetRequiredService(); - var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionMenus.Select(x => x.RequiredPermissionName).ToArray()); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray()); - var toBeDeletedMenus = new List(); - foreach (var menu in requiredPermissionMenus) + var toBeDeleted = new List(); + foreach (var menu in requiredPermissionItems) { if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted) { - toBeDeletedMenus.Add(menu); + toBeDeleted.Add(menu); } } - RemoveMenus(menuWithItems, toBeDeletedMenus); + RemoveMenus(menuWithItems, toBeDeleted); } } protected virtual void GetRequiredPermissionNameMenus(IHasMenuItems menuWithItems, List output) { - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - if (!menuItem.RequiredPermissionName.IsNullOrWhiteSpace()) + if (!item.RequiredPermissionName.IsNullOrWhiteSpace()) { - output.Add(menuItem); + output.Add(item); } - GetRequiredPermissionNameMenus(menuItem, output); + GetRequiredPermissionNameMenus(item, output); } } @@ -83,17 +83,17 @@ namespace Volo.Abp.UI.Navigation { menuWithItems.Items.RemoveAll(toBeDeleted.Contains); - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - RemoveMenus(menuItem, toBeDeleted); + RemoveMenus(item, toBeDeleted); } } protected virtual void NormalizeMenu(IHasMenuItems menuWithItems) { - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - NormalizeMenu(menuItem); + NormalizeMenu(item); } menuWithItems.Items.Normalize(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs new file mode 100644 index 0000000000..f8f9d21b27 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Permissions +{ + public class FakePermissionStore : IPermissionStore, ITransientDependency + { + public Task IsGrantedAsync(string name, string providerName, string providerKey) + { + var result = (name.Contains("MyComponent1") || name.Contains("MyComponent3")); + return Task.FromResult(result); + } + + public Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in names) + { + result.Result.Add(name, (name.Contains("MyComponent1") || name.Contains("MyComponent3")) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited); + } + + return Task.FromResult(result); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..ef706a6c0a --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs @@ -0,0 +1,16 @@ +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Permissions +{ + public class TestPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup("TestGroup"); + + group.AddPermission("MyComponent1"); + group.AddPermission("MyComponent2"); + group.AddPermission("MyComponent3"); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs new file mode 100644 index 0000000000..70ca907fac --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using NSubstitute; +using Shouldly; +using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars; +using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars +{ + public class Toolbar_Tests : AbpAspNetCoreMvcUiThemeSharedTestBase + { + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Configure(options => + { + options.Contributors.Add(new MyToolbarContributor()); + options.Contributors.Add(new MyToolbarContributor2()); + }); + + var claims = new List() { + new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"), + }; + + var identity = new ClaimsIdentity(claims); + var claimsPrincipal = new ClaimsPrincipal(identity); + var principalAccessor = Substitute.For(); + principalAccessor.Principal.Returns(ci => claimsPrincipal); + Thread.CurrentPrincipal = claimsPrincipal; + + var themeManager = Substitute.For(); + themeManager.CurrentTheme.Returns(x => null); + services.Replace(ServiceDescriptor.Singleton(themeManager)); + } + + [Fact] + public void AbpToolbarOptions_Should_Contain_Contributors() + { + var options = GetRequiredService>().Value; + options.Contributors.Count.ShouldBe(2); + options.Contributors.ShouldContain(x => x.GetType() == typeof(MyToolbarContributor)); + options.Contributors.ShouldContain(x => x.GetType() == typeof(MyToolbarContributor2)); + } + + [Fact] + public async Task ToolbarManager_Should_Return_Toolbar() + { + var toolbarManager = GetRequiredService(); + var toolbar = await toolbarManager.GetAsync(StandardToolbars.Main); + + toolbar.Items.Count.ShouldBe(3); + toolbar.Items[0].ComponentType.ShouldBe(typeof(MyComponent1)); + toolbar.Items[1].ComponentType.ShouldBe(typeof(MyComponent3)); + toolbar.Items[2].ComponentType.ShouldBe(typeof(MyComponent4)); + } + + public class MyToolbarContributor : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name != StandardToolbars.Main) + { + return Task.CompletedTask; + } + + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent1), requiredPermissionName: "MyComponent1")); + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent2), requiredPermissionName: "MyComponent2")); + + return Task.CompletedTask; + } + } + + public class MyToolbarContributor2 : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name != StandardToolbars.Main) + { + return Task.CompletedTask; + } + + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent3), requiredPermissionName: "MyComponent3")); + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent4))); + + return Task.CompletedTask; + } + } + + public class MyComponent1 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent1"); + } + } + + public class MyComponent2 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent2"); + } + } + + public class MyComponent3 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent3"); + } + } + + public class MyComponent4 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent4"); + } + } + } +} From e8342fe2edf10508ce61954dbe47bb2e56d55689 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 26 Feb 2021 22:23:04 +0800 Subject: [PATCH 3/3] Use HashSet for toBeDeleted. --- .../Toolbars/ToolbarManager.cs | 2 +- .../Volo/Abp/Ui/Navigation/MenuManager.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs index 1f48b2825b..d6fc02f153 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs @@ -54,7 +54,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars var permissionChecker = serviceProvider.GetRequiredService(); var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray()); - var toBeDeleted = new List(); + var toBeDeleted = new HashSet(); foreach (var item in requiredPermissionItems) { if (grantResult.Result[item.RequiredPermissionName!] != PermissionGrantResult.Granted) diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index d1f3ee330a..28ac86d4d2 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -53,7 +53,7 @@ namespace Volo.Abp.UI.Navigation var permissionChecker = serviceProvider.GetRequiredService(); var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray()); - var toBeDeleted = new List(); + var toBeDeleted = new HashSet(); foreach (var menu in requiredPermissionItems) { if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted) @@ -79,7 +79,7 @@ namespace Volo.Abp.UI.Navigation } } - protected virtual void RemoveMenus(IHasMenuItems menuWithItems, List toBeDeleted) + protected virtual void RemoveMenus(IHasMenuItems menuWithItems, HashSet toBeDeleted) { menuWithItems.Items.RemoveAll(toBeDeleted.Contains);