Last active
June 18, 2022 11:55
-
-
Save alasvant/5cfe6b643ecef37cdc31d9a85abc7383 to your computer and use it in GitHub Desktop.
Optimizely World blog post: Custom placeholders in Optimizely Forms submission emails. https://world.optimizely.com/blogs/Antti-Alasvuo/Dates/2022/6/custom-place-holders-in-optimizely-forms-submission-emails/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Web; | |
using EPiServer; | |
using EPiServer.Core; | |
using EPiServer.Forms; | |
using EPiServer.Forms.Core.Internal; | |
using EPiServer.Forms.Core.Models; | |
using EPiServer.ServiceLocation; | |
using EPiServer.Web.Routing; | |
namespace AlloyWithFind.Features.FormsCustomPlaceholder | |
{ | |
public class FormsSystemColumnsPlaceholderProvider : IPlaceHolderProvider | |
{ | |
/// <summary> | |
/// IContentLoader service. | |
/// </summary> | |
private readonly Injected<IContentLoader> _contentLoader; | |
/// <summary> | |
/// IUrlResolver service. | |
/// </summary> | |
private readonly Injected<IUrlResolver> _urlResolver; | |
// Note the placeholder key value is what is displayed in placeholder dropdown | |
/// <summary> | |
/// Form submitted placeholder. | |
/// </summary> | |
private const string FormSubmittedTimestamp = "Form submitted"; | |
/// <summary> | |
/// Form submitted by user placeholder. | |
/// </summary> | |
private const string FormSubmittedBy = "Form submitted by"; | |
/// <summary> | |
/// Form submitted from page placeholder. | |
/// </summary> | |
private const string FormSubmittedFromPage = "Form submit page"; | |
/// <summary> | |
/// Text to use if the user was anonymous. | |
/// </summary> | |
private const string AnonymousUsername = "anonymous"; | |
/// <inheritdoc/> | |
public int Order | |
{ | |
get => 100; | |
set { } | |
} | |
/// <inheritdoc/> | |
public IEnumerable<PlaceHolder> ExtraPlaceHolders => new PlaceHolder[] { | |
new PlaceHolder(FormSubmittedTimestamp, null), | |
new PlaceHolder(FormSubmittedBy, null), | |
new PlaceHolder(FormSubmittedFromPage, null) | |
}; | |
/// <inheritdoc/> | |
public IEnumerable<PlaceHolder> ProcessPlaceHolders(IEnumerable<PlaceHolder> availablePlaceHolders, FormIdentity formIden, HttpRequestBase requestBase = null, Submission submissionData = null, bool performHtmlEncode = true) | |
{ | |
if (availablePlaceHolders == null) | |
{ | |
// the DefaultPlaceHolderProvider throw null exception too if the availablePlaceHolders is null | |
// the interface documentation doesn't say anything about exceptions (which ones should be thrown) | |
// so do it the same way | |
throw new ArgumentNullException(nameof(availablePlaceHolders)); | |
} | |
// get the submission data | |
var data = submissionData?.Data; | |
// if we don't have data, then do nothing | |
if (data == null) | |
{ | |
return availablePlaceHolders; | |
} | |
foreach (var ph in availablePlaceHolders) | |
{ | |
if (FormSubmittedTimestamp.Equals(ph.Key, StringComparison.Ordinal)) | |
{ | |
// get the submitted timestamp | |
if (data.TryGetSubmitTime(out DateTime submitted)) | |
{ | |
data.TryGetLanguage(out string languageCode); | |
try | |
{ | |
// the timestamp is DateTimeKind.Utc, format the timestamp using | |
// the forms culture or the default culture | |
ph.Value = $"{submitted.ToString(GetCultureInfo(languageCode))} UTC"; | |
} | |
catch {} | |
} | |
} | |
else if(FormSubmittedBy.Equals(ph.Key, StringComparison.Ordinal)) | |
{ | |
// get the submitted by user | |
if (data.TryGetSubmitUser(out string username)) | |
{ | |
ph.Value = string.IsNullOrWhiteSpace(username) ? AnonymousUsername : username; | |
} | |
else | |
{ | |
ph.Value = AnonymousUsername; | |
} | |
} | |
else if (FormSubmittedFromPage.Equals(ph.Key, StringComparison.Ordinal)) | |
{ | |
// get the form hosted page | |
if (data.TryGetHostedPage(out ContentReference hostedPage)) | |
{ | |
LoaderOptions loadingOptions; | |
// try to get the language code | |
if (data.TryGetLanguage(out string languageCode)) | |
{ | |
loadingOptions = new LoaderOptions { LanguageLoaderOption.FallbackWithMaster(GetCultureInfo(languageCode)) }; | |
} | |
else | |
{ | |
loadingOptions = new LoaderOptions { LanguageLoaderOption.MasterLanguage() }; | |
} | |
// try to load the content in the forms language and fallback to masterlanguage | |
if (_contentLoader.Service.TryGet(hostedPage, loadingOptions, out PageData page)) | |
{ | |
// and then resolve the url using the language the content was actually loaded in | |
var pageUrl = _urlResolver.Service.GetUrl(page); | |
ph.Value = $"{page.Name}, {pageUrl}"; | |
} | |
} | |
} | |
} | |
return availablePlaceHolders; | |
} | |
/// <summary> | |
/// Get <see cref="CultureInfo"/> object using the <paramref name="languageCode"/>. | |
/// </summary> | |
/// <param name="languageCode">Language code (<see cref="CultureInfo.Name"/>).</param> | |
/// <returns><see cref="CultureInfo"/> object created using the <paramref name="languageCode"/> or if there was an exception then a CultureInfo object is returned using the <see cref="Constants.DefaultCulture"/>.</returns> | |
private static CultureInfo GetCultureInfo(string languageCode) | |
{ | |
try | |
{ | |
if (!string.IsNullOrEmpty(languageCode)) | |
{ | |
return CultureInfo.GetCultureInfo(languageCode); | |
} | |
} | |
catch {} | |
// this is fallback if there was an exception or the languageCode was null | |
return CultureInfo.GetCultureInfo(Constants.DefaultCulture); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment