Browse Source

Merge branch 'dev' into volo/issue/5635

pull/7889/head
Yunus Emre Kalkan 6 years ago
parent
commit
15ae41f6db
  1. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs
  2. 31
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs
  3. 7
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs
  4. 58
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs
  5. 28
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs
  6. 16
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs
  7. 129
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs
  8. 2
      framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj
  9. 21
      framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs
  10. 28
      framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs
  11. 60
      framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs
  12. 24
      framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs

8
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;
}
}
}
}

31
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<AbpToolbarOptions> options,
IOptions<AbpToolbarOptions> 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<IPermissionChecker>();
var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray());
var toBeDeleted = new HashSet<ToolbarItem>();
foreach (var item in requiredPermissionItems)
{
if (grantResult.Result[item.RequiredPermissionName!] != PermissionGrantResult.Granted)
{
toBeDeleted.Add(item);
}
}
toolbar.Items.RemoveAll(toBeDeleted.Contains);
}
}
}
}
}

7
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; set; }
/// <summary>
/// Can be used to store a custom object related to this menu item. Optional.
/// </summary>
@ -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();
}

58
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<AbpNavigationOptions> options,
IOptions<AbpNavigationOptions> 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,14 +43,60 @@ namespace Volo.Abp.UI.Navigation
return menu;
}
protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, IHasMenuItems menuWithItems)
{
var requiredPermissionItems = new List<ApplicationMenuItem>();
GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionItems);
if (requiredPermissionItems.Any())
{
var permissionChecker = serviceProvider.GetRequiredService<IPermissionChecker>();
var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray());
var toBeDeleted = new HashSet<ApplicationMenuItem>();
foreach (var menu in requiredPermissionItems)
{
if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted)
{
toBeDeleted.Add(menu);
}
}
RemoveMenus(menuWithItems, toBeDeleted);
}
}
protected virtual void GetRequiredPermissionNameMenus(IHasMenuItems menuWithItems, List<ApplicationMenuItem> output)
{
foreach (var item in menuWithItems.Items)
{
if (!item.RequiredPermissionName.IsNullOrWhiteSpace())
{
output.Add(item);
}
GetRequiredPermissionNameMenus(item, output);
}
}
protected virtual void RemoveMenus(IHasMenuItems menuWithItems, HashSet<ApplicationMenuItem> toBeDeleted)
{
menuWithItems.Items.RemoveAll(toBeDeleted.Contains);
foreach (var item in menuWithItems.Items)
{
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();
}
}
}
}

28
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<bool> IsGrantedAsync(string name, string providerName, string providerKey)
{
var result = (name.Contains("MyComponent1") || name.Contains("MyComponent3"));
return Task.FromResult(result);
}
public Task<MultiplePermissionGrantResult> 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);
}
}
}

16
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");
}
}
}

129
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<AbpToolbarOptions>(options =>
{
options.Contributors.Add(new MyToolbarContributor());
options.Contributors.Add(new MyToolbarContributor2());
});
var claims = new List<Claim>() {
new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"),
};
var identity = new ClaimsIdentity(claims);
var claimsPrincipal = new ClaimsPrincipal(identity);
var principalAccessor = Substitute.For<ICurrentPrincipalAccessor>();
principalAccessor.Principal.Returns(ci => claimsPrincipal);
Thread.CurrentPrincipal = claimsPrincipal;
var themeManager = Substitute.For<IThemeManager>();
themeManager.CurrentTheme.Returns(x => null);
services.Replace(ServiceDescriptor.Singleton<IThemeManager>(themeManager));
}
[Fact]
public void AbpToolbarOptions_Should_Contain_Contributors()
{
var options = GetRequiredService<IOptions<AbpToolbarOptions>>().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<ToolbarManager>();
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");
}
}
}
}

2
framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj

@ -9,6 +9,8 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.UI.Navigation\Volo.Abp.UI.Navigation.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Authorization\Volo.Abp.Authorization.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup>

21
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<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor1());
options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor2());
});
}
}
}

28
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<bool> IsGrantedAsync(string name, string providerName, string providerKey)
{
var result = (name.Contains("Administration") || name.Contains("Dashboard")) && !name.Contains("SubMenu1");
return Task.FromResult(result);
}
public Task<MultiplePermissionGrantResult> 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);
}
}
}

60
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<MenuManager_Tests.TestModule>
public class MenuManager_Tests : AbpIntegratedTest<AbpUiNavigationTestModule>
{
private readonly IMenuManager _menuManager;
@ -16,6 +20,24 @@ namespace Volo.Abp.UI.Navigation
_menuManager = ServiceProvider.GetRequiredService<IMenuManager>();
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
protected override void AfterAddApplication(IServiceCollection services)
{
var claims = new List<Claim>() {
new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"),
};
var identity = new ClaimsIdentity(claims);
var claimsPrincipal = new ClaimsPrincipal(identity);
var principalAccessor = Substitute.For<ICurrentPrincipalAccessor>();
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<AbpNavigationOptions>(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;

24
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");
}
}
}
Loading…
Cancel
Save