Skip to content

Commit

Permalink
Retrieving User object using expression
Browse files Browse the repository at this point in the history
  • Loading branch information
barthamark committed Feb 28, 2023
1 parent b6f343a commit a87e941
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using Lombiq.HelpfulExtensions.Extensions.Workflows.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Localization;
using OrchardCore.Users;
using OrchardCore.Users.Models;
using OrchardCore.Users.Services;
using OrchardCore.Workflows.Abstractions.Models;
using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Models;
Expand All @@ -22,28 +22,27 @@ public class GenerateResetPasswordTokenTask : TaskActivity
private readonly LinkGenerator _linkGenerator;
private readonly IHttpContextAccessor _hca;
private readonly UserManager<IUser> _userManager;
private readonly IUserService _userService;
private readonly IWorkflowExpressionEvaluator _expressionEvaluator;
private readonly IWorkflowScriptEvaluator _workflowScriptEvaluator;

public override string Name => nameof(GenerateResetPasswordTokenTask);
public override LocalizedString DisplayText => T["Generate reset password token"];
public override LocalizedString Category => T["User"];

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

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

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

Expand All @@ -52,15 +51,13 @@ public GenerateResetPasswordTokenTask(
LinkGenerator linkGenerator,
IHttpContextAccessor hca,
UserManager<IUser> userManager,
IUserService userService,
IWorkflowExpressionEvaluator expressionEvaluator)
IWorkflowScriptEvaluator workflowScriptEvaluator)
{
T = localizer;
_linkGenerator = linkGenerator;
_hca = hca;
_userManager = userManager;
_userService = userService;
_expressionEvaluator = expressionEvaluator;
_workflowScriptEvaluator = workflowScriptEvaluator;
}

public override IEnumerable<Outcome> GetPossibleOutcomes(
Expand All @@ -72,39 +69,34 @@ public override async Task<ActivityExecutionResult> ExecuteAsync(
WorkflowExecutionContext workflowContext,
ActivityContext activityContext)
{
var userPropertyKey = !string.IsNullOrEmpty(UserPropertyKey.Expression)
? await _expressionEvaluator.EvaluateAsync(UserPropertyKey, workflowContext, encoder: null)
var user = !string.IsNullOrEmpty(User.Expression)
? await _workflowScriptEvaluator.EvaluateAsync(User, workflowContext)
: null;

var user = string.IsNullOrEmpty(userPropertyKey)
? workflowContext.Input.GetMaybe("User") as User
: workflowContext.Properties.GetMaybe(userPropertyKey) as User ??
await _userService.GetUserByUniqueIdAsync(workflowContext.Properties.GetMaybe(userPropertyKey) as string) as User;

if (user == null) return Outcomes("Error");

var resetPasswordTokenPropertyKey = !string.IsNullOrEmpty(ResetPasswordTokenPropertyKey.Expression)
? await _expressionEvaluator.EvaluateAsync(ResetPasswordTokenPropertyKey, workflowContext, encoder: null)
: null;
var resetPasswordUrlPropertyKey = !string.IsNullOrEmpty(ResetPasswordUrlPropertyKey.Expression)
? await _expressionEvaluator.EvaluateAsync(ResetPasswordUrlPropertyKey, workflowContext, encoder: null)
: null;

var generatedToken = await _userManager.GeneratePasswordResetTokenAsync(user);
user.ResetToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(generatedToken));
if (!string.IsNullOrEmpty(resetPasswordTokenPropertyKey))
var resetPasswordUrl = _linkGenerator.GetUriByAction(
_hca.HttpContext,
"ResetPassword",
"ResetPassword",
new { area = "OrchardCore.Users", code = user.ResetToken });

workflowContext.LastResult = new GenerateResetPasswordTokenResult
{
ResetPasswordToken = user.ResetToken,
ResetPasswordUrl = resetPasswordUrl,
};

if (!string.IsNullOrEmpty(ResetPasswordTokenPropertyKey))
{
workflowContext.Properties[resetPasswordTokenPropertyKey] = user.ResetToken;
workflowContext.Properties[ResetPasswordTokenPropertyKey] = user.ResetToken;
}

if (!string.IsNullOrEmpty(resetPasswordUrlPropertyKey))
if (!string.IsNullOrEmpty(ResetPasswordUrlPropertyKey))
{
var resetPasswordUrl = _linkGenerator.GetUriByAction(
_hca.HttpContext,
"ResetPassword",
"ResetPassword",
new { area = "OrchardCore.Users", code = user.ResetToken });
workflowContext.Properties[resetPasswordUrlPropertyKey] = resetPasswordUrl;
workflowContext.Properties[ResetPasswordUrlPropertyKey] = resetPasswordUrl;
}

return Outcomes("Done");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.Extensions.Localization;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Mvc.ModelBinding;
using OrchardCore.Users.Models;
using OrchardCore.Workflows.Display;
using OrchardCore.Workflows.Models;
using System.Threading.Tasks;
Expand All @@ -21,28 +21,19 @@ public GenerateResetPasswordTokenTaskDisplayDriver(IStringLocalizer<GenerateRese

protected override void EditActivity(GenerateResetPasswordTokenTask activity, GenerateResetPasswordTokenTaskViewModel model)
{
model.UserPropertyKey = activity.UserPropertyKey.Expression;
model.ResetPasswordTokenPropertyKey = activity.ResetPasswordTokenPropertyKey.Expression;
model.ResetPasswordUrlPropertyKey = activity.ResetPasswordUrlPropertyKey.Expression;
model.UserExpression = activity.User.Expression;
model.ResetPasswordTokenPropertyKey = activity.ResetPasswordTokenPropertyKey;
model.ResetPasswordUrlPropertyKey = activity.ResetPasswordUrlPropertyKey;
}

public override async Task<IDisplayResult> UpdateAsync(GenerateResetPasswordTokenTask model, IUpdateModel updater)
{
var viewModel = new GenerateResetPasswordTokenTaskViewModel();
if (await updater.TryUpdateModelAsync(viewModel, Prefix))
{
model.UserPropertyKey = new WorkflowExpression<string>(viewModel.UserPropertyKey);
model.ResetPasswordTokenPropertyKey = new WorkflowExpression<string>(viewModel.ResetPasswordTokenPropertyKey);
model.ResetPasswordUrlPropertyKey = new WorkflowExpression<string>(viewModel.ResetPasswordUrlPropertyKey);

if (string.IsNullOrEmpty(viewModel.ResetPasswordTokenPropertyKey) &&
string.IsNullOrEmpty(viewModel.ResetPasswordUrlPropertyKey))
{
updater.ModelState.AddModelError(
Prefix,
"TokenOrUrlIsRequired",
T["A value is required for either the token or the URL property key."]);
}
model.User = new WorkflowExpression<User>(viewModel.UserExpression);
model.ResetPasswordTokenPropertyKey = viewModel.ResetPasswordTokenPropertyKey;
model.ResetPasswordUrlPropertyKey = viewModel.ResetPasswordUrlPropertyKey;
}

return Edit(model);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Lombiq.HelpfulExtensions.Extensions.Workflows.Models;

public class GenerateResetPasswordTokenResult
{
public string ResetPasswordToken { get; set; }
public string ResetPasswordUrl { get; set; }
}
8 changes: 7 additions & 1 deletion Lombiq.HelpfulExtensions/Extensions/Workflows/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Fluid;
using Lombiq.HelpfulExtensions.Extensions.Workflows.Activities;
using Lombiq.HelpfulExtensions.Extensions.Workflows.Drivers;
using Lombiq.HelpfulExtensions.Extensions.Workflows.Models;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Modules;
using OrchardCore.Workflows.Helpers;
Expand All @@ -9,6 +11,10 @@ namespace Lombiq.HelpfulExtensions.Extensions.Workflows;
[Feature(FeatureIds.ResetPasswordActivity)]
public class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services) =>
public override void ConfigureServices(IServiceCollection services)
{
services.AddActivity<GenerateResetPasswordTokenTask, GenerateResetPasswordTokenTaskDisplayDriver>();
services.Configure<TemplateOptions>(option =>
option.MemberAccessStrategy.Register<GenerateResetPasswordTokenResult>());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.ComponentModel.DataAnnotations;

namespace Lombiq.HelpfulExtensions.Extensions.Workflows.ViewModels;

public class GenerateResetPasswordTokenTaskViewModel
{
public string UserPropertyKey { get; set; }
[Required]
public string UserExpression { get; set; }
public string ResetPasswordTokenPropertyKey { get; set; }
public string ResetPasswordUrlPropertyKey { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
<i class="fa fa-user" aria-hidden="true"></i>@Model.Activity.GetTitleOrDefault(() => T["Generate Reset Password Token"])
</h4>
</header>

<span>@T["User expression: <em>{0}</em>", Model.Activity.User?.Expression]</span>
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
@model Lombiq.HelpfulExtensions.Extensions.Workflows.ViewModels.GenerateResetPasswordTokenTaskViewModel

<div class="mb-3" asp-validation-class-for="UserPropertyKey">
<label asp-for="UserPropertyKey">@T["User Property Key"]</label>
<input type="text" asp-for="UserPropertyKey" class="form-control"></input>
<span asp-validation-for="UserPropertyKey"></span>
<span class="hint">@T["Key of the property in the Workflow context dictionary that contains the user's ID or the User object. If it's empty, it'll try to find the User object in the Workflow input. With Liquid support."]</span>
<div class="mb-3" asp-validation-class-for="UserExpression">
<label asp-for="UserExpression">@T["User Expression"]</label>
<input type="text" asp-for="UserExpression" class="form-control code" />
<span asp-validation-for="UserExpression"></span>
<span class="hint">@T["Enter a JavaScript expression that evaluates to the User object."]</span>
</div>
<div class="mb-3" asp-validation-class-for="ResetPasswordTokenPropertyKey">
<label asp-for="ResetPasswordTokenPropertyKey">@T["Reset Password Token Property Key"]</label>
<input type="text" asp-for="ResetPasswordTokenPropertyKey" class="form-control"></input>
<input type="text" asp-for="ResetPasswordTokenPropertyKey" class="form-control" />
<span asp-validation-for="ResetPasswordTokenPropertyKey"></span>
<span class="hint">@T["Key of the property in the Workflow context where this Task will set the reset password token to. Optionally, leave it empty and set the URL field. With Liquid support."]</span>
<span class="hint">@T["Optional key of the property in the Workflow context where this Task will set the reset password token to."]</span>
</div>
<div class="mb-3" asp-validation-class-for="ResetPasswordUrlPropertyKey">
<label asp-for="ResetPasswordUrlPropertyKey">@T["Reset Password URL Property Key"]</label>
<input type="text" asp-for="ResetPasswordUrlPropertyKey" class="form-control"></input>
<input type="text" asp-for="ResetPasswordUrlPropertyKey" class="form-control" />
<span asp-validation-for="ResetPasswordUrlPropertyKey"></span>
<span class="hint">@T["Key of the property in the Workflow context where this Task will set the reset password URL to. Optionally, leave it empty and set the token field. With Liquid support."]</span>
<span class="hint">@T["Optional key of the property in the Workflow context where this Task will set the reset password URL to."]</span>
</div>
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Gives all external links the `target="_blank"` attribute.

### Reset Password activity

Adds a workflow activity that generates a reset password token for the specified user. You can define the source of the User object or ID using activity parameters. It will set the token or the URL to the workflow context to a key that you define as an activity parameter.
Adds a workflow activity that generates a reset password token for the specified user. You can define the source of the User object using a JavaScript expression. It will set the token and the URL to the workflow `LastResult` property and optionally it can set them to the `Properties` dictionary to a key that you define as an activity parameter.

## Contributing and support

Expand Down

0 comments on commit a87e941

Please sign in to comment.