From b0e95169ea8e3911409cb50e5995be5116f9927b Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 May 2021 20:05:57 +0800 Subject: [PATCH 1/5] Add Simple State Checker document. Resolve #8895 --- docs/en/Authorization.md | 32 +----- docs/en/SimpleStateChecker.md | 125 +++++++++++++++++++++++ docs/en/UI/AspNetCore/Navigation-Menu.md | 19 ++-- docs/en/UI/AspNetCore/Toolbars.md | 4 +- docs/en/docs-nav.json | 4 + 5 files changed, 141 insertions(+), 43 deletions(-) create mode 100644 docs/en/SimpleStateChecker.md diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 2632f3c88a..73ee36af8f 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -265,37 +265,7 @@ myGroup.AddPermission("Book_Creation") #### Creating a Custom Permission Dependency -Any class implements the `IPermissionStateProvider` interface can disable a permission based on a custom condition. - -**Example:** - -````csharp -public class MyCustomPermissionStateProvider : IPermissionStateProvider -{ - public Task IsEnabledAsync(PermissionStateContext context) - { - // You can implement your own logic here. - return Task.FromResult( - context.Permission.Name.StartsWith("Acme.BookStore")); - } -} -```` - -Then you can add `MyCustomPermissionStateProvider` to any permission definition, using the `AddStateProviders` extension method: - -````csharp -myGroup.AddPermission("Book_Creation") - .AddStateProviders(new MyCustomPermissionStateProvider()); -```` - -Or you can globally add your custom provider to make it working for all permissions: - -````csharp -Configure(options => -{ - options.GlobalStateProviders.Add(); -}); -```` +`PermissionDefinition` supports state check, Please refer to [Simple State Checker's documentation](SimpleStateChecker.md) ## IAuthorizationService diff --git a/docs/en/SimpleStateChecker.md b/docs/en/SimpleStateChecker.md new file mode 100644 index 0000000000..077f2be477 --- /dev/null +++ b/docs/en/SimpleStateChecker.md @@ -0,0 +1,125 @@ +# Simple State Checker + +The **state** of some objects may depend on multiple conditions, such as some permissions are required, features need to be enabled, or it is only for special users and roles are available. + +## Definition state checker. + +Any class can inherit `IHasSimpleStateCheckers` to support state checks. + +````csharp +public class MyObject : IHasSimpleStateCheckers +{ + public int Id { get; set; } + + public List> SimpleStateCheckers { get; } + + public MyObject() + { + SimpleStateCheckers = new List>(); + } +} +```` + +The `MyObject` class contains a collection of state checkers, you can add your custom checkers to it. + +````csharp +public class MyObjectStateChecker : ISimpleStateChecker +{ + public Task IsEnabledAsync(SimpleStateCheckerContext context) + { + var currentUser = context.ServiceProvider.GetRequiredService(); + return Task.FromResult(currentUser.IsInRole("Admin")); + } +} +```` + +````csharp +var myobj = new MyObject() +{ + Id = 100 +}; + +myobj.SimpleStateCheckers.Add(new MyObjectStateChecker()); +```` + +## Definition global state checker. + +`AbpSimpleStateCheckerOptions` is the options class that used to set the global state checkers for specific object. + +Example: Add global state for `MyObject`: + +````csharp +services.Configure>(options => +{ + options.GlobalSimpleStateCheckers.Add(); + //options.GlobalSimpleStateCheckers.Add<>(); //Add more global state checkers +}); +```` + +> Write this inside the `ConfigureServices` method of your module. + +### Check the state + +You can inject `ISimpleStateCheckerManager` service to check state. + +````csharp +bool enabled = await stateCheckerManager.IsEnabledAsync(myobj); +```` + +### Batch check the states + +If there are many instance items that require state checking, there may be performance problems. + +In this case, you can implement `ISimpleBatchStateChecker`. It can check multiple items at once. +You need to make sure that the same `ISimpleBatchStateChecker` instance is added to the `SimpleStateCheckers` of multiple instances. + +> `SimpleBatchStateCheckerBase` inherits the `ISimpleBatchStateChecker` interface and implements the `IsEnabledAsync` method of a single object by default. + +````csharp +public class MyObjectBatchStateChecker : SimpleBatchStateCheckerBase +{ + public override Task> IsEnabledAsync(SimpleBatchStateCheckerContext context) + { + var result = new SimpleStateCheckerResult(context.States); + + foreach (var myObject in context.States) + { + if (myObject.Id > 100) + { + result[myObject] = true; + } + } + + return Task.FromResult(result); + } +} +```` + +````csharp +var myobj1 = new MyObject() +{ + Id = 100 +}; +var myobj2 = new MyObject() +{ + Id = 99 +}; + +var myObjectBatchStateChecker = new MyObjectBatchStateChecker(); + +myobj1.SimpleStateCheckers.Add(myObjectBatchStateChecker); +myobj2.SimpleStateCheckers.Add(myObjectBatchStateChecker); + +SimpleStateCheckerResult stateCheckerResult = await stateCheckerManager.IsEnabledAsync(new []{ myobj1, myobj2 }); +```` + +## Built-in state checker + +The `PermissionDefinition`, `ApplicationMenuItem` and `ToolbarItem` objects have implemented state checks and have built-in general state checkers, you can directly use their extension methods. + +````csharp +RequireAuthenticated(); +RequirePermissions(bool requiresAll, params string[] permissions); +RequireFeatures(bool requiresAll, params string[] features); +RequireGlobalFeatures(bool requiresAll, params Type[] globalFeatures); +```` \ No newline at end of file diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index 8480590f50..97e3d1a47d 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -104,7 +104,6 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt * `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. * `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. * `cssClass` (`string`): Additional string classes for the menu item. -* `RequiredPermissionName` (`string`): The required permission name, this menu item will be removed if this permission is not granted. ### Authorization @@ -121,21 +120,21 @@ if (await context.IsGrantedAsync("MyPermissionName")) } ```` -For the authorization, you can use `RequiredPermissionName` as a shortcut. It is also more performant, ABP optimizes the permission check for all the items. +For the authorization, you can use `RequirePermissions` extension method as a shortcut. It is also more performant, ABP optimizes the permission check for all the items. ````csharp context.Menu.AddItem( new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"]) .AddItem(new ApplicationMenuItem( - name: "MyProject.Crm.Customers", - displayName: l["Menu:Customers"], - url: "/crm/customers", - requiredPermissionName: "MyProject.Crm.Customers") + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + .RequirePermissions("MyProject.Crm.Customers") ).AddItem(new ApplicationMenuItem( - name: "MyProject.Crm.Orders", - displayName: l["Menu:Orders"], - url: "/crm/orders", - requiredPermissionName: "MyProject.Crm.Orders") + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + .RequirePermissions("MyProject.Crm.Orders") ) ); ```` diff --git a/docs/en/UI/AspNetCore/Toolbars.md b/docs/en/UI/AspNetCore/Toolbars.md index 66ec7519b8..d82150b47e 100644 --- a/docs/en/UI/AspNetCore/Toolbars.md +++ b/docs/en/UI/AspNetCore/Toolbars.md @@ -61,10 +61,10 @@ if (await context.IsGrantedAsync("MyPermissionName")) } ```` -You can use `RequiredPermissionName` as a shortcut. It is also more performant, ABP optimizes the permission check for all the items. +You can use `RequirePermissions` extension method as a shortcut. It is also more performant, ABP optimizes the permission check for all the items. ````csharp -context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(NotificationViewComponent), requiredPermissionName: "MyPermissionName")); +context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(NotificationViewComponent)).RequirePermissions("MyPermissionName")); ```` This class adds the `NotificationViewComponent` as the first item in the `Main` toolbar. diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 0a7722de78..9a1bad449e 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -379,6 +379,10 @@ { "text": "Cancellation Token Provider", "path": "Cancellation-Token-Provider.md" + }, + { + "text": "Simple State Checker", + "path": "SimpleStateChecker.md" } ] }, From 7d80f5ce83e23e64edbeef87f904876b9423946b Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 May 2021 09:15:33 +0800 Subject: [PATCH 2/5] Update docs/en/SimpleStateChecker.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Halil İbrahim Kalkan --- docs/en/SimpleStateChecker.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/SimpleStateChecker.md b/docs/en/SimpleStateChecker.md index 077f2be477..7dc853158d 100644 --- a/docs/en/SimpleStateChecker.md +++ b/docs/en/SimpleStateChecker.md @@ -113,7 +113,7 @@ myobj2.SimpleStateCheckers.Add(myObjectBatchStateChecker); SimpleStateCheckerResult stateCheckerResult = await stateCheckerManager.IsEnabledAsync(new []{ myobj1, myobj2 }); ```` -## Built-in state checker +## Built-in State Checkers The `PermissionDefinition`, `ApplicationMenuItem` and `ToolbarItem` objects have implemented state checks and have built-in general state checkers, you can directly use their extension methods. @@ -122,4 +122,4 @@ RequireAuthenticated(); RequirePermissions(bool requiresAll, params string[] permissions); RequireFeatures(bool requiresAll, params string[] features); RequireGlobalFeatures(bool requiresAll, params Type[] globalFeatures); -```` \ No newline at end of file +```` From e083250cd8210129d1842118230e914c168c4a33 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 May 2021 09:15:38 +0800 Subject: [PATCH 3/5] Update docs/en/SimpleStateChecker.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Halil İbrahim Kalkan --- docs/en/SimpleStateChecker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/SimpleStateChecker.md b/docs/en/SimpleStateChecker.md index 7dc853158d..9d4c243f72 100644 --- a/docs/en/SimpleStateChecker.md +++ b/docs/en/SimpleStateChecker.md @@ -58,7 +58,7 @@ services.Configure>(options => > Write this inside the `ConfigureServices` method of your module. -### Check the state +## Check the state You can inject `ISimpleStateCheckerManager` service to check state. From 510fc3c4eec7f2ad74024e79401a64542f47b338 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 May 2021 09:15:43 +0800 Subject: [PATCH 4/5] Update docs/en/SimpleStateChecker.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Halil İbrahim Kalkan --- docs/en/SimpleStateChecker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/SimpleStateChecker.md b/docs/en/SimpleStateChecker.md index 9d4c243f72..b0529ee519 100644 --- a/docs/en/SimpleStateChecker.md +++ b/docs/en/SimpleStateChecker.md @@ -42,7 +42,7 @@ var myobj = new MyObject() myobj.SimpleStateCheckers.Add(new MyObjectStateChecker()); ```` -## Definition global state checker. +## Definition Global State Checkers `AbpSimpleStateCheckerOptions` is the options class that used to set the global state checkers for specific object. From 62b96f9796dd013318eb31d2a3ab9cdc876058fa Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 May 2021 09:15:49 +0800 Subject: [PATCH 5/5] Update docs/en/SimpleStateChecker.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Halil İbrahim Kalkan --- docs/en/SimpleStateChecker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/SimpleStateChecker.md b/docs/en/SimpleStateChecker.md index b0529ee519..584fef1592 100644 --- a/docs/en/SimpleStateChecker.md +++ b/docs/en/SimpleStateChecker.md @@ -1,6 +1,6 @@ # Simple State Checker -The **state** of some objects may depend on multiple conditions, such as some permissions are required, features need to be enabled, or it is only for special users and roles are available. +The simple state checking system can be used to enable/disable an object based on some dynamic conditions. For example, you can disable a menu item on the user interface, if the current user has not granted for a given permission. The simple state checking system provides a generic way to define and check such conditions. ## Definition state checker.