Search code examples
umbracorecaptcha

Creating a Custom field type in Umbraco to supports the invisible enterprise reCaptcha


Hello Stackoverflow community.

Currently, I found that Umbraco doesn't have an option to support the enterprise invisible reCaptcha. After following a bit along I did came across this documentation where we can create custom field type and have a custom validation logic.

What I have done so far :

Add a new class

ReCaptchaEnterprise.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Umbraco.Forms.Core.Enums;
using Umbraco.Forms.Core.Models;
using Umbraco.Forms.Core.Services;

namespace FormsExtensions
{
    public class ReCaptchaEnterprise : Umbraco.Forms.Core.FieldType
    {
        public ReCaptchaEnterprise()
        {
            Id = new Guid("e3ab6a21-bc99-4cb8-999e-ad01203d61bd"); // Replace this!
            Name = "ReCaptcha Enterprise";
            Description = "Render a custom reCaptcha enterprise field.";
            Icon = "icon-autofill";
            SortOrder = 10;
            FieldTypeViewName = "FieldType.ReCaptchaEnterprise.cshtml";
        }
        
        // Custom validation in here which will occur when the form is submitted.
        // Any strings returned will cause the submission to be considered invalid.
        // Returning an empty collection of strings will indicate that it's valid to proceed.
        public override IEnumerable<string> ValidateField(Form form, Field field, IEnumerable<object> postedValues, HttpContext context, IPlaceholderParsingService placeholderParsingService, IFieldTypeStorage fieldTypeStorage)
        {
            var returnStrings = new List<string>();

            if (!postedValues.Any(value => value.ToString().ToLower().Contains("custom")))
            {
                returnStrings.Add("You need to include 'custom' in the field!");
            }

            var reCaptchaResponse = context.Request.Form["g-recaptcha-response"].ToString();
            Console.WriteLine("+++++++++++++++++++++ReCaptcha response+++++++++++++++++++++++++++" + reCaptchaResponse);
            
            // Also validate it against the default method (to handle mandatory fields and regular expressions)
            return base.ValidateField(form, field, postedValues, context, placeholderParsingService, fieldTypeStorage, returnStrings);
        }
    }    
}

Partial View

FieldType.ReCaptchaEnterprise.html

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage

@using Umbraco.Forms.Web
@using Microsoft.Extensions.Configuration
@model Umbraco.Forms.Web.Models.FieldViewModel
@inject IConfiguration Configuration
@{
    var siteKey = Configuration.GetSection("ReCaptchaEnterprise")["SiteKey"];
    if (!string.IsNullOrEmpty(siteKey))
    {
        Html.AddFormThemeScriptFile("https://www.google.com/recaptcha/enterprise.js?render=" + siteKey);
        <div class="g-recaptcha"
             data-sitekey="@siteKey"
             data-callback="onSubmit" data-size="invisible">
        </div>
         <input type="hidden" name="g-recaptcha-response" />
         
        <script type="application/javascript">
            function  onSubmit(event){
                event.preventDefault();
                grecaptcha.execute();
            }
        </script>
    }
    else
    {
        <p class="error">ERROR: reCAPTCHA is missing the Site Key. Please update the configuration to include a value.</p>
    }
} 

Registering new field as dependency

using FormsExtensions;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Forms.Core.Providers;

namespace Web
{
    public class ReCaptchaEnterpriseComposer: IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.WithCollectionBuilder<FieldCollectionBuilder>()
                .Add<ReCaptchaEnterprise>();
        }
    }    
} 

Umbraco backoffice view

App_plugins/UmbracoFotms/backoffice/common/fieldtypes/ReCaptchaEnterprise.html

<div class="g-recaptcha" data-sitekey="<site-key>" data-size="invisible"></div>

I am able to add the reCaptcha enterprise in the form. However, when I go to Content and add it over there via Rich Text Editor > Macro the following exception is thrown.

Received an error from the server An error occurred Cannot bind source type Umbraco.Forms.Web.Models.FieldViewModel to model type Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent.

Exception Details Umbraco.Cms.Web.Common.ModelBinders.ModelBindingException, Umbraco.Web.Common, Version=12.0.1.0, Culture=neutral, PublicKeyToken=null: Cannot bind source type Umbraco.Forms.Web.Models.FieldViewModel to model type Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent.

I have no idea what is going wrong I am debugging the issue since last 2 days cannot find any solution.

I will really appreciate any leads to resolve this issue or if you can share your experience regarding how you created a custom field in Umbraco. Thank you so much for your time for reading through my question until here.

I have tried following other packages that have done something similar to implement reCaptcha but it is of no help until now.


Solution

  • If someone faces similar issue. I have removed @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage from the Partial View and now everything started working.