Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to Remove User from a Role (Issue #14632) #14652

Merged
merged 14 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@using OrchardCore.Workflows.ViewModels
@using OrchardCore.Workflows.Helpers
@using OrchardCore.Users.Workflows.Activities
@using OrchardCore.Users.Workflows.ViewModels
@model ActivityViewModel<RemoveUserRoleTask>
<header>
<h4><i class="fa-solid fa-user" aria-hidden="true"></i>@Model.Activity.GetTitleOrDefault(() => T["Remove user from a role"])</h4>
</header>
<em>@T["{0} from role {1}", Model.Activity.UserName, Model.Activity.RoleName]</em>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@using OrchardCore.Users.Workflows.ViewModels
@model RemoveUserRoleTaskViewModel

<div class="mb-3" asp-validation-class-for="UserName">
<label asp-for="UserName">@T["UserName"]</label>
<input type="text" asp-for="UserName" class="form-control code" />
<span asp-validation-for="UserName"></span>
<span class="hint">@T["The User to update. With Liquid support."]</span>
</div>

<div class="mb-3" asp-validation-class-for="RoleName">
<label asp-for="RoleName">@T["RoleName"]</label>
<input type="text" asp-for="RoleName" class="form-control code" />
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
<span asp-validation-for="RoleName"></span>
<span class="hint">@T["The Role to remove. With Liquid support."]</span>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h4 class="card-title"><i class="fa-solid fa-user" aria-hidden="true"></i>@T["Remove user from role"]</h4>
<p>@T["Removes a user from a role."]</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@using OrchardCore.Workflows.ViewModels
@using OrchardCore.Workflows.Helpers
@using OrchardCore.Users.Workflows.Activities
@using OrchardCore.Users.Workflows.ViewModels
@model ActivityViewModel<SelectUsersInRoleTask>
<header>
<h4><i class="fa-solid fa-user" aria-hidden="true"></i>@Model.Activity.GetTitleOrDefault(() => T["Select users in role"])</h4>
</header>
<em>@T["Stores users from role {0} to {1}", Model.Activity.RoleName, Model.Activity.OutputKeyName]</em>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@using OrchardCore.Users.Workflows.ViewModels
@model SelectUsersInRoleTaskViewModel

<div class="mb-3" asp-validation-class-for="OutputKeyName">
<label asp-for="OutputKeyName">@T["OutputKeyName"]</label>
<input type="text" asp-for="OutputKeyName" class="form-control code" />
<span asp-validation-for="OutputKeyName"></span>
<span class="hint">@T["The Output Key Name to save list. With Liquid support."]</span>
</div>

<div class="mb-3" asp-validation-class-for="RoleName">
<label asp-for="RoleName">@T["RoleName"]</label>
<input type="text" asp-for="RoleName" class="form-control code" />
<span asp-validation-for="RoleName"></span>
<span class="hint">@T["The Role to search for. With Liquid support."]</span>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h4 class="card-title"><i class="fa-solid fa-user" aria-hidden="true"></i>@T["Select users in role"]</h4>
<p>@T["Select users in role."]</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;
using OrchardCore.Users.Models;
using OrchardCore.Users.Services;
using OrchardCore.Workflows.Abstractions.Models;
using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Models;
using OrchardCore.Workflows.Services;

namespace OrchardCore.Users.Workflows.Activities
{
public class RemoveUserRoleTask : TaskActivity
{
private readonly UserManager<IUser> _userManager;
private readonly IUserService _userService;
private readonly IWorkflowExpressionEvaluator _expressionEvaluator;
protected readonly IStringLocalizer S;

public RemoveUserRoleTask(UserManager<IUser> userManager, IUserService userService, IWorkflowExpressionEvaluator expressionvaluator, IStringLocalizer<RemoveUserRoleTask> localizer)
{
_userManager = userManager;
_userService = userService;
_expressionEvaluator = expressionvaluator;
S = localizer;
}

public override string Name => nameof(RemoveUserRoleTask);

public override LocalizedString DisplayText => S["Remove User Role Task"];

public override LocalizedString Category => S["User"];

public WorkflowExpression<string> UserName
{
get => GetProperty(() => new WorkflowExpression<string>());
set => SetProperty(value);
}

public WorkflowExpression<string> RoleName
{
get => GetProperty(() => new WorkflowExpression<string>());
set => SetProperty(value);
}

public override IEnumerable<Outcome> GetPossibleOutcomes(WorkflowExecutionContext workflowContext, ActivityContext activityContext)
{
return Outcomes(S["Done"], S["Failed"]);
}

public override async Task<ActivityExecutionResult> ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityContext activityContext)
{
var userName = await _expressionEvaluator.EvaluateAsync(UserName, workflowContext, null);
var roleName = await _expressionEvaluator.EvaluateAsync(RoleName, workflowContext, null);

var user = (User)await _userService.GetUserAsync(userName);

if (user != null)
{
if (user.RoleNames.Contains(roleName))
{
await _userManager.RemoveFromRoleAsync(user, roleName);
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
}

return Outcomes("Done");
}
else
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
{
return Outcomes("Failed");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;
using OrchardCore.Users.Models;
using OrchardCore.Users.Services;
using OrchardCore.Workflows.Abstractions.Models;
using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Models;
using OrchardCore.Workflows.Services;

namespace OrchardCore.Users.Workflows.Activities
{
public class SelectUsersInRoleTask : TaskActivity
{
private readonly UserManager<IUser> _userManager;
private readonly IUserService _userService;
private readonly IWorkflowExpressionEvaluator _expressionEvaluator;
protected readonly IStringLocalizer S;

public SelectUsersInRoleTask(UserManager<IUser> userManager, IUserService userService, IWorkflowExpressionEvaluator expressionvaluator, IStringLocalizer<SelectUsersInRoleTask> localizer)
{
_userManager = userManager;
_userService = userService;
_expressionEvaluator = expressionvaluator;
S = localizer;
}

public override string Name => nameof(SelectUsersInRoleTask);

public override LocalizedString DisplayText => S["Select Users in Role Task"];

public override LocalizedString Category => S["User"];

public WorkflowExpression<string> OutputKeyName
{
get => GetProperty(() => new WorkflowExpression<string>());
set => SetProperty(value);
}

public WorkflowExpression<string> RoleName
{
get => GetProperty(() => new WorkflowExpression<string>());
set => SetProperty(value);
}

public override IEnumerable<Outcome> GetPossibleOutcomes(WorkflowExecutionContext workflowContext, ActivityContext activityContext)
{
return Outcomes(S["Done"], S["Failed"]);
}

public override async Task<ActivityExecutionResult> ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityContext activityContext)
{
var propKeyName = await _expressionEvaluator.EvaluateAsync(OutputKeyName, workflowContext, null);
var roleName = await _expressionEvaluator.EvaluateAsync(RoleName, workflowContext, null);

if (!string.IsNullOrEmpty(propKeyName) && !string.IsNullOrEmpty(roleName))
{
var usersInRole = await _userManager.GetUsersInRoleAsync(roleName);
if (usersInRole.Count > 0)
{
workflowContext.Output[propKeyName] = usersInRole.Select(u => (u as User).UserId).ToArray();
return Outcomes("Done");
}
}
return Outcomes("Failed");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using OrchardCore.Workflows.Display;
using OrchardCore.Workflows.Models;
using OrchardCore.Users.Workflows.Activities;
using OrchardCore.Users.Workflows.ViewModels;

namespace OrchardCore.Users.Workflows.Drivers
{
public class RemoveUserRoleTaskDisplayDriver : ActivityDisplayDriver<RemoveUserRoleTask, RemoveUserRoleTaskViewModel>
{
protected override void EditActivity(RemoveUserRoleTask activity, RemoveUserRoleTaskViewModel model)
{
model.UserName = activity.UserName.Expression;
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
model.RoleName = activity.RoleName.Expression;
}

protected override void UpdateActivity(RemoveUserRoleTaskViewModel model, RemoveUserRoleTask activity)
{
activity.UserName = new WorkflowExpression<string>(model.UserName);
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
activity.RoleName = new WorkflowExpression<string>(model.RoleName);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using OrchardCore.Users.Workflows.Activities;
using OrchardCore.Users.Workflows.ViewModels;
using OrchardCore.Workflows.Display;
using OrchardCore.Workflows.Models;

namespace OrchardCore.Users.Workflows.Drivers
{
public class SelectUsersInRoleTaskDisplayDriver : ActivityDisplayDriver<SelectUsersInRoleTask, SelectUsersInRoleTaskViewModel>
{
protected override void EditActivity(SelectUsersInRoleTask activity, SelectUsersInRoleTaskViewModel model)
{
model.OutputKeyName = activity.OutputKeyName.Expression;
model.RoleName = activity.RoleName.Expression;
}

protected override void UpdateActivity(SelectUsersInRoleTaskViewModel model, SelectUsersInRoleTask activity)
{
activity.OutputKeyName = new WorkflowExpression<string>(model.OutputKeyName);
activity.RoleName = new WorkflowExpression<string>(model.RoleName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public override void ConfigureServices(IServiceCollection services)
services.AddActivity<UserLoggedInEvent, UserLoggedInEventDisplayDriver>();
services.AddScoped<IUserEventHandler, UserEventHandler>();
services.AddActivity<AssignUserRoleTask, AssignUserRoleTaskDisplayDriver>();
services.AddActivity<RemoveUserRoleTask, RemoveUserRoleTaskDisplayDriver>();
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
services.AddActivity<SelectUsersInRoleTask, SelectUsersInRoleTaskDisplayDriver>();
services.AddActivity<ValidateUserTask, ValidateUserTaskDisplayDriver>();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;

namespace OrchardCore.Users.Workflows.ViewModels
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
{
public class RemoveUserRoleTaskViewModel
{
[Required]
public string UserName { get; set; }

[Required]
public string RoleName { get; set; }
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;

namespace OrchardCore.Users.Workflows.ViewModels
{
public class SelectUsersInRoleTaskViewModel
{
[Required]
public string OutputKeyName { get; set; }

[Required]
public string RoleName { get; set; }
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
}
}