Sitecore 9 Forms Part-2 – Google Recaptcha Field

Hello Sitecorians,

I’ve been exploring Sitecore Forms and implemented the Google Re-captcha form element within the Sitecore forms. Re-captcha is the basic requirement for the form submission process and in order to implement this, we’ve to write some code to it.

We will go through step by step process to implement the Google Recaptcha with Sitecore Forms using the custom form element. And will create a generic component which you can use for any other form as well.

How to do ?

First we will create the sitecore template changes,

We will need the following fields for Recapthca Field

  • Public Key
  • Private Key
  • Error Message

Core DB Changes :

1. Go to the “/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Common/Details” and duplicate the “FieldName” Item.

2. Update the “FormLabel” to “Private Key” and “BindingConfiguration” like below screenshot

PrivateKey

3. Do the same steps to the remaining two fields.

Now we need to create the Property Editor.

  1. Go to the “/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Settings” Item.
  2. Duplicate the “SingleLineText” and Update the details section.
  3. Add the newly created details items to “GoogleRecapthca” item like below screenshot

Recpatcha details

Master DB changes :

  1. Go to the “/sitecore/templates/System/Forms/Fields” and duplicate the “/sitecore/templates/System/Forms/Fields/Input” Item.
  2. We need to add the below fields in the “Google Recaptcha” Item and create the _StandardValues as well.
  • Public Key
  • Private Key
  • Error Message

Google Recaptcha Template

3. Update the PrivateKey and PublicKey in _StandardValues .

Google Recaptcha Standard Value

 Code Changes : 

Create the new class “GoogleRecaptcha” like below,

using Sitecore.Data.Items;
using Sitecore.ExperienceForms.Mvc.Models.Fields;

namespace Sitecore.Scientist.Forms.Fields
{
    public class GoogleRecaptcha : StringInputViewModel
    {
        public string PublicKey { get; set; }

        public string PrivateKey { get; set; }

        public string ErrorMessage { get; set; }

        protected override void InitItemProperties(Item item)
        {
            base.InitItemProperties(item);

            PublicKey = StringUtil.GetString(item.Fields["Public Key"]);
            PrivateKey = StringUtil.GetString(item.Fields["Private Key"]);
            ErrorMessage = StringUtil.GetString(item.Fields["Error Message"]);
        }

        protected override void UpdateItemFields(Item item)
        {
            base.UpdateItemFields(item);

            item.Fields["Public Key"].SetValue(PublicKey, true);
            item.Fields["Private Key"].SetValue(PrivateKey, true);
            item.Fields["Error Message"].SetValue(ErrorMessage, true);
        }
    }
}

Create the new view “GoogleRecaptcha.cshtml” and place under the “Views\FormBuilder\FieldTemplates”

@using Sitecore.ExperienceForms.Mvc.Html
@model Sitecore.Scientist.Forms.Fields.GoogleRecaptcha

https://www.google.com/recaptcha/api.js

<span class=”field-validation-error” id=”captchaError-@Html.IdFor(m => Model.Value)” style=”display:none”>@Model.ErrorMessage</span>
<input id=”@Html.IdFor(m => Model.Value)” name=”@Html.NameFor(m => Model.Value)” class=”@Model.CssClass” value=”@Model.Value” type=”hidden” data-sc-tracking=”@Model.IsTrackingEnabled” data-sc-field-name=”@Model.Name” @Html.GenerateUnobtrusiveValidationAttributes(m => m.Value) />
@Html.ValidationMessageFor(m => Model.Value)

if ($(‘#’+’@Html.IdFor(m => Model.Value)’).parent(‘form’)) {
$($(‘#’ + ‘@Html.IdFor(m => Model.Value)’).parent(‘form’)).submit(function () {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘span[data-valmsg-for=”@Html.NameFor(m => Model.Value)’).hide();
var recaptchaResponse = grecaptcha.getResponse();
if (recaptchaResponse.length == 0) {
document.getElementById(‘captchaError-‘ + ‘@Html.IdFor(m => Model.Value)’).value = $(‘#’ + ‘@Html.IdFor(m => Model.Value)’).data(‘val-required’);
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “block”;
return false;
}
else {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘#’+’@Html.IdFor(m => Model.Value)’).val(recaptchaResponse);
return true;
}
});
}
function captchaCallback() {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘span[data-valmsg-for=”@Html.NameFor(m => Model.Value)’).hide();
if (recaptchaResponse.length == 0) {
document.getElementById(‘captchaError-‘ + ‘@Html.IdFor(m => Model.Value)’).value = $(‘#’ + ‘@Html.IdFor(m => Model.Value)’).data(‘val-required’);
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “block”;
}
else {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘#’+’@Html.IdFor(m => Model.Value)’).val(recaptchaResponse);
}
}

Coding part is done .Its time to create the field.Create the new field  “Google Recaptcha” under the “/sitecore/system/Settings/Forms/Field Types/Security” path and update red marked field. Recaptcha field Recaptcha field2 Lets create the form Captcha form We are not done yet.Its very important to create the server side validator for the recaptcha. Create the new class called “CaptchaValidator.cs” like below,

using Newtonsoft.Json;
using Sitecore.Data;
using Sitecore.ExperienceForms.Mvc.Models.Fields;
using Sitecore.ExperienceForms.Mvc.Models.Validation;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Web.Mvc;

namespace Sitecore.Scientist.Forms.Validator
{
    public class CaptchaResponse
    {
        [JsonProperty("success")]
        public bool Success { get; set; }

        [JsonProperty("error-codes")]
        public List ErrorMessage { get; set; }
    }

    public class CaptchaValidator : ValidationElement
    {

        public override IEnumerable ClientValidationRules
        {
            get
            {
                if (string.IsNullOrEmpty(this.PrivateKey))
                {
                    yield break;
                }
            }
        }

        protected virtual string PrivateKey
        {
            get;
            set;
        }

        protected virtual string Title
        {
            get;
            set;
        }
        protected virtual string FieldName
        {
            get;
            set;
        }
        public CaptchaValidator(ValidationDataModel validationItem) : base(validationItem)
        {

        }

        public override void Initialize(object validationModel)
        {
            base.Initialize(validationModel);
            StringInputViewModel stringInputViewModel = validationModel as StringInputViewModel;
            if (stringInputViewModel != null)
            {
                var fieldItem = Context.Database.GetItem(ID.Parse(stringInputViewModel.ItemId));
               if(fieldItem!=null)
                {
                    this.PrivateKey = fieldItem["Private Key"];
                }
                this.Title = stringInputViewModel.Title;
                this.FieldName = stringInputViewModel.Name;
            }
        }

        public override ValidationResult Validate(object value)
        {
            if (value == null)
            {
                return ValidationResult.Success;
            }
            var isCaptchaValid = ValidateCaptcha((string)value, this.PrivateKey);
            if (!isCaptchaValid)
            {
                return new ValidationResult(this.FormatMessage(new object[] { this.Title }));
            }
            return ValidationResult.Success;
        }
        public static bool ValidateCaptcha(string response, string secret)
        {
            var client = new WebClient();
            var reply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secret, response));

            var captchaResponse = JsonConvert.DeserializeObject(reply);

            return System.Convert.ToBoolean(captchaResponse.Success);
        }
    }
}

Create the new Captchavalidator under the “/sitecore/system/Settings/Forms/Validations” like below screenshot

captchavalidator

Select the CaptchaValidator in GoogleRecaptcha Validations.

captchavalidator selection

we are done for creating the google recaptcha field .Let’s test the field

Captcha testing

1_CBiTTy_Wpw_r62BC7H7WMA

Thanks to Nikki Punjabi . I have referred his post and created this post.

Lazy developers don’t like to create this field from all of the above steps.That’s why i created the sitecore package for the lazy guys.Please download the package from this Google Recaptcha SC9 Form Field-V1.0.zip

After installing the package, if you are getting the below error then update your recaptcha “Private Key” and “Public Key”.

Captcha invalid domain

Download the source code from Github.

Thanks you for visiting my blog . Happy Coding.

Sitecore 9 Forms Part-1 – Form with Email Exist Validation

Hello Sitecorians,

Hope you’re playing around with Sitecore 9 and with the newly introduced cool features in it.There is lot to do with the Sitecore forms .I will explain that in upcoming posts.In this post i am going to explain the basic sitecore 9 form with Email exist validation.

Every subscription form email exist validation is very basic requirement.We can do that in very simple way.Please follow my steps,

How to do ?

  1. Create the new validator class “EmailExistValidator”
using Microsoft.Extensions.DependencyInjection;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.DependencyInjection;
using Sitecore.ExperienceForms.Data;
using Sitecore.ExperienceForms.Mvc.Models.Fields;
using Sitecore.ExperienceForms.Mvc.Models.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;

namespace Sitecore.Scientist.Forms.Validator
{
    public class EmailExistValidator : ValidationElement<string>
    {
        public readonly string FormTemplateId = "{6ABEE1F2-4AB4-47F0-AD8B-BDB36F37F64C}";

        private IFormDataProvider _dataProvider;


        protected virtual IFormDataProvider FormDataProvider
        {
            get
            {
                IFormDataProvider formDataProvider = this._dataProvider;
                if (formDataProvider == null)
                {
                    IFormDataProvider service = ServiceLocator.ServiceProvider.GetService<IFormDataProvider>();
                    IFormDataProvider formDataProvider1 = service;
                    this._dataProvider = service;
                    formDataProvider = formDataProvider1;
                }
                return formDataProvider;
            }
        }

        public override IEnumerable<ModelClientValidationRule> ClientValidationRules
        {
            get
            {
                if (string.IsNullOrEmpty(this.FormId))
                {
                    yield break;
                }
            }
        }

        protected virtual string FormId
        {
            get;
            set;
        }

        protected virtual string Title
        {
            get;
            set;
        }
        protected virtual string FieldName
        {
            get;
            set;
        }
        public EmailExistValidator(ValidationDataModel validationItem) : base(validationItem)
        {

        }

        public override void Initialize(object validationModel)
        {
            base.Initialize(validationModel);
            StringInputViewModel stringInputViewModel = validationModel as StringInputViewModel;
            if (stringInputViewModel != null)
            {
                var fieldItem = Context.Database.GetItem(ID.Parse(stringInputViewModel.ItemId));
                var formItem = GetFormItem(fieldItem);
                if (formItem != null)
                {
                    this.FormId = formItem.ID.ToString();
                }
                this.Title = stringInputViewModel.Title;
                this.FieldName = stringInputViewModel.Name;
            }
        }

        public override ValidationResult Validate(object value)
        {
            if (value == null)
            {
                return ValidationResult.Success;
            }
            if (!string.IsNullOrEmpty(this.FormId))
            {
                var formId = Guid.Parse(this.FormId);
                var data = this.FormDataProvider.GetEntries(formId, null, null);
                foreach (var item in data)
                {
                    var emailValue = item.Fields.Where(x => x.FieldName == this.FieldName).FirstOrDefault();
                    if (emailValue != null && emailValue.Value.ToLower() == value.ToString().ToLower())
                    {
                        return new ValidationResult(this.FormatMessage(new object[] { this.Title }));
                    }

                }
                return ValidationResult.Success;
            }
            return new ValidationResult(this.FormatMessage(new object[] { this.Title }));
        }
        public Item GetFormItem(Item sitecoreItem)
        {
            if (sitecoreItem == null)
                return null;
            Item parent = sitecoreItem.Parent;
            if (parent.TemplateID == ID.Parse(this.FormTemplateId))
            {
                return parent;
            }
            else if (ItemIDs.RootID == parent.ID)
            {
                return null;
            }
            else
            {
                return GetFormItem(parent);
            }
        }
    }
}

2. Now we have to create the EmailExistValidator under the “/sitecore/system/Settings/Forms/Validations” in master database.

3. Just duplicate the Emailvalidator and update the values like below screenshot

EmailExistValidator

4. Create the new form with Email field ,

Subscribe form

5. Add the newly created “EmailExistValidator” validation to the email field.

add validation

6 . We are almost done.Lets go for the testing.

Exist Validation

415w

Thanks for visiting my blog.Download the source code from Github.

Redirect Module for Sitecore 9

Simple redirect module for the Sitecore 9 and Sitecore 8. It has the following options for the redirect

  1. Sitecore Internal Items Redirect
  2. Regex Options
  3. Broken Links

It Supports 3 type of redirection

  1. Permanent Redirect (301)
  2. Temporary Redirect (302)
  3. Server Transfer

How to Use the Redirect Module

  1. Download and install the Redirect Module from the market place.Alternatively you can download from Simple Redirect Module-V2.0.1.zip
  2. Add these entry to your Site config file.
  3. You can keep the separate settings for each when you are using the multi site.

redirectSettingsId=”{23F429BA-9BBF-4FDD-9BCD-1E7E46A0D029}”

redirect settings.png

How to Use the Redirect Module

Internal Item Redirect

  1. Add the new redirect item

Redirect

Map the target Item and Redirect Url

Redirect internal

2. Regex

Redirect Regex

For Ex. ^/test3(/.*)?$ – /test$1

Target Url : http://sitecoresite/test3/home4?test=1

Redirect Url :  http://sitecoresite/test/home4?test=1

3. Redirect Map

Redirect Map

Download the Source code from Github.