Skip to content

Commit

Permalink
Add Recipe Roles permission behavior (#17254)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored Dec 18, 2024
1 parent 21ab7d7 commit 07bc378
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 12 deletions.
35 changes: 33 additions & 2 deletions src/OrchardCore.Modules/OrchardCore.Roles/Recipes/RolesStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,33 @@ protected override async Task HandleAsync(RecipeExecutionContext context)
if (role is Role r)
{
r.RoleDescription = roleEntry.Description;
r.RoleClaims.RemoveAll(c => c.ClaimType == Permission.ClaimType);

if (roleEntry.PermissionBehavior == PermissionBehavior.Replace)
{
// At this point, we know we are replacing permissions.
// Remove all existing permission so we can add the replacements later.
r.RoleClaims.RemoveAll(c => c.ClaimType == Permission.ClaimType);
}

if (!await _systemRoleNameProvider.IsAdminRoleAsync(roleName))
{
r.RoleClaims.AddRange(roleEntry.Permissions.Select(RoleClaim.Create));
if (roleEntry.PermissionBehavior == PermissionBehavior.Remove)
{
// Materialize this list to prevent an exception.
var permissions = r.RoleClaims.Where(c => c.ClaimType == Permission.ClaimType && roleEntry.Permissions.Contains(c.ClaimValue)).ToArray();

foreach (var permission in permissions)
{
r.RoleClaims.Remove(permission);
}
}
else
{
var permissions = roleEntry.Permissions.Select(RoleClaim.Create)
.Where(newClaim => !r.RoleClaims.Exists(existingClaim => existingClaim.ClaimType == newClaim.ClaimType && existingClaim.ClaimValue == newClaim.ClaimValue));

r.RoleClaims.AddRange(permissions);
}
}
}

Expand Down Expand Up @@ -83,4 +105,13 @@ public sealed class RolesStepRoleModel
public string Description { get; set; }

public string[] Permissions { get; set; }

public PermissionBehavior PermissionBehavior { get; set; }
}

public enum PermissionBehavior
{
Replace,
Add,
Remove,
}
51 changes: 42 additions & 9 deletions src/docs/reference/modules/Roles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,50 @@ A sample of a roles configuration step:

```json
{
"name": "roles",
"Roles": [
"steps": [
{
"Name": "Journalist",
"Description" "Journalist Role",
"Permissions": ["PublishContent", "EditContent"]
},
"name": "roles",
"Roles": [
{
"Name": "Journalist",
"Description" "Journalist Role",
"PermissionBehavior": "Replace",
"Permissions": ["PublishContent", "EditContent"]
},
{
"Name": "Subscriber",
"Description" "Subscriber Role",
"PermissionBehavior": "Replace",
"Permissions": []
}
]
}
]
}
```

As of version 3.0, the `Roles` recipe includes the ability to define specific permission behaviors, giving you greater control over how permissions are managed within a role. The following behaviors are available:

- **Replace**: This behavior removes all existing permissions associated with the role and replaces them with the new permissions from the `Permissions` collection. This is the default behavior.
- **Add**: This behavior adds the new permission(s) from the `Permissions` collection to the role, but only if they do not already exist. Existing permissions are left unchanged.
- **Remove**: This behavior removes the specified permission(s) from the role’s existing permissions based on the `Permissions` collection.

### Example: Adding a New Permission to a Role

For instance, to add the "CanChat" permission to the `Subscriber` role, use the following configuration:

```json
{
"steps": [
{
"Name": "Subscriber",
"Description" "Subscriber Role",
"Permissions": []
"name": "roles",
"Roles": [
{
"Name": "Subscriber",
"PermissionBehavior": "Add",
"Permissions": ["CanChat"]
}
]
}
]
}
Expand Down
14 changes: 13 additions & 1 deletion src/docs/releases/3.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,21 @@ This change is designed to simplify your integration process and make it easier

## Change Log

### Roles Module

#### Permission Behavior Added to Roles Recipe Step

The `Roles` recipe now includes the ability to define specific permission behaviors, allowing you to control how permissions are managed within a role. The following behaviors are available:

- **Replace**: This behavior removes all existing permissions associated with the role and replaces them with the new permissions from the `Permissions` collection. This is the default behavior.
- **Add**: This behavior adds the new permission(s) from the `Permissions` collection to the role, but only if they do not already exist. It does not affect the existing permissions.
- **Remove**: This behavior removes the specified permission(s) in the `Permissions` collection from the role’s existing permissions.

For more info about the new `PermissionBehavior`, check out the [documentation](../reference/modules/Roles/README.md).

### ReCaptcha

### New ReCaptcha Shape
#### New ReCaptcha Shape

A new `ReCaptcha` shape has been introduced, enabling you to render the ReCaptcha challenge using a customizable shape. For more details, please refer to the [documentation](../reference/modules/ReCaptcha/README.md).

Expand Down

0 comments on commit 07bc378

Please # to comment.