November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Hi Erik,
The problem with this approach, as you probably noted, is that returning a SubmissionActorResult
with a CancelSubmit
value of true
gives you an error message. To fix this, on your success path you could call base.Run(input)
and on your failure path you could return null
:
var honeypot = submittedData.FirstOrDefault(x => x.Key == "HoneypotElementBlock");
if (honeypot.Value != null && honeypot.Value.ToString().Length > 0)
{
return base.Run(input);
}
return null;
I think this'll get the Actor you have above working as expected. However, it's worth noting that at this point your submission has already been saved to the database (the SaveDataToStorageActor
runs first). That may or may not be problematic depending on whether you care about that spam data being saved anywhere. Any other actors you have may also have been executed at this point, which could be an issue if you intend to use webhooks in the future for example.
In an ideal world you'd register an Actor to execute before the SaveDataToStorageActor
(which can be done by implementing the ISyncOrderedSubmissionActor
), but as already mentioned whilst setting the CancelSubmit
to true
will stop the rest of the actors but present the user with an error.
I think the best option (probably) is to move your logic to a custom ActorsExecutingService
, something like this:
public class HoneypotActorsExecutingService : ActorsExecutingService
{
private readonly IFormDataRepository _formDataRepository;
private readonly IFormRepository _formRepository;
public HoneypotActorsExecutingService(IFormDataRepository formDataRepository, IFormRepository formRepository)
{
_formDataRepository = formDataRepository;
_formRepository = formRepository;
}
public override IEnumerable<object> ExecuteActors(Submission submission, FormContainerBlock formContainer,
FormIdentity formIden, HttpRequestBase request, HttpResponseBase response, bool isFormFinalizedSubmission)
{
if (HasValidHoneypot(submission, formIden))
{
return base.ExecuteActors(submission, formContainer, formIden, request, response,
isFormFinalizedSubmission);
}
return new object[0];
}
/// <summary>
/// Indicates whether the form has a completed honeypot element.
/// </summary>
/// <param name="submission">The submission.</param>
/// <param name="formIden">The form identity.</param>
/// <returns><c>true</c> if the form has a valid honeypot element, otherwise <c>false</c></returns>
private bool HasValidHoneypot(Submission submission, FormIdentity formIden)
{
var dataFriendlyNameInfos = _formRepository.GetDataFriendlyNameInfos(formIden);
var submittedData = _formDataRepository.TransformSubmissionDataWithFriendlyName(
submission.Data, dataFriendlyNameInfos, true).ToList();
// The form doesn't contain a honeypot element, return true
if (!submittedData.Any(x => x.Key.Equals(nameof(HoneypotElementBlock), StringComparison.Ordinal)))
{
return true;
}
var honeypot =
submittedData.FirstOrDefault(x => x.Key.Equals(nameof(HoneypotElementBlock), StringComparison.Ordinal));
return !string.IsNullOrEmpty(honeypot.Value?.ToString());
}
}
This prevents any actors being executed if the honeypot trap has been triggered.
You'll need to register this with a configurable module:
[InitializableModule]
public class DependencyResolverInitialization : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.ConfigurationComplete += (o, e) =>
{
context.Services.AddSingleton<ActorsExecutingService, HoneypotActorsExecutingService>();
};
}
public void Initialize(InitializationEngine context) {}
public void Uninitialize(InitializationEngine context) {}
}
Hope that works out for you!
Hi Jake.
Thank you, it works perfectly!
Well put, I had also figured out I had to add a own custom actor that way but your solution is much better with handling the other actors besides the mailactor.
Since Captcha isn't compliant with WCAG and my customer doesn't like the idea of google recaptcha I've decided to do a honeypot element instead.
I've created the element and am no trying to validate it before it sends out. It's all sent by mail.
Now when the forms get's submitted I've managed to hit the run method but this is where I get stuck. I don't now how to handle it from here.
Sorry if the code is messy, been trying all kinds of different solutions since I'm fairly new to all this, mostly there for example.
But basically what I want is if the honeypot contains any value i don't want to send the mail but it should look like everything went well for the user.
Any help is appreciated.
Thanks