Within the company where I work there was a wish to send users a notification when they were tagged in a post on the timeline, this is unfortunately not in the standard of Dynamics.
Let’s get started
To understand how these mention(s) look in the database I looked at the data that is put in the entity post with XRMToolbox. The following is stored in the column largetext:
@[8,GUID,"Arjan ter Heegde"] test
To build this wish I initially thought of a Power Automate Flow, as I have used it more often to create notifications. Unfortunately, it is not possible with Power Automate to use RegEx out-of-the box which we need to parse the GUID of the tagged user(s), so I had no choice but to switch to a plug-in. I only had experience with updating existing Dynamics 365 CE plug-ins, i never created one by myself, so this was a nice challenge to try in my spare time.
The plug-in
I wrote the following code to achieve that all users who are mentioned in a post get a notification:
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Metadata;
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.IdentityModel.Metadata;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography.Xml;
using Microsoft.Xrm.Sdk.Extensions;
namespace Ath.Plugins.PostMention
{
public class PostMentionPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(null); // SYSTEM user
Entity entity = (Entity)context.InputParameters["Target"];
Entity e = service.Retrieve(entity.LogicalName, entity.Id, new ColumnSet("source"));
OptionSetValue source = (OptionSetValue)e["source"];
if (source.Value == 2)
{
string input = (string)entity["largetext"];
string pattern = @"@\[8,(.*?),(.*?)\]"; // @[8,*,"*"]
MatchCollection matches = Regex.Matches(input, pattern);
if (matches.Count > 0)
{
foreach (Match match in matches) // for each mention
{
string guidString = match.Groups[1].Value;
Guid guid;
if (Guid.TryParse(guidString, out guid)) // check if GUID is valid
{
Entity systemUser = service.Retrieve("systemuser", guid, new ColumnSet("systemuserid"));
if (systemUser != null)
{
if (entity.Contains("createdby") && entity["createdby"] is EntityReference)
{
EntityReference createdByRef = (EntityReference)entity["createdby"];
Entity createdBy = service.Retrieve(createdByRef.LogicalName, createdByRef.Id, new ColumnSet("fullname"));
if (entity.Contains("regardingobjectid") && entity["regardingobjectid"] is EntityReference)
{
Guid regardingObjectId = ((EntityReference)entity["regardingobjectid"]).Id;
string regardingEntityName = ((EntityReference)entity["regardingobjectid"]).LogicalName;
EntityMetadata entityMetadata = service.GetEntityMetadata(regardingEntityName);
string entityDisplayName = entityMetadata.DisplayName.UserLocalizedLabel.Label.ToLower();
string fullNameTaggedBy = createdBy.GetAttributeValue<string>("fullname");
// https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/clientapi/send-in-app-notifications?tabs=sdk
Entity appNotification = new Entity("appnotification");
appNotification["title"] = "You've been mentioned on a timeline";
appNotification["ownerid"] = new EntityReference("systemuser", guid);
appNotification["body"] = $"You've been mentioned on an {entityDisplayName} timeline by {fullNameTaggedBy}.";
appNotification["icontype"] = new OptionSetValue(100000004);
appNotification["toasttype"] = new OptionSetValue(200000000);
appNotification["ttlinseconds"] = Convert.ToInt32(1209600); // 14 days
var url = "?pagetype=entityrecord&etn=" + regardingEntityName + "&id=" + regardingObjectId;
appNotification["data"] = "{\"actions\":[{\"title\":\"View post\",\"data\":{\"url\":\"" + url + "\"}}]}";
Guid notificationId = service.Create(appNotification);
}
}
}
}
}
}
}
}
}
}
C#Register the plug-in on the Create message, post primary entity, Post-operation event stage, Asynchronous execution mode and run in user’s context Calling User
If you are unable to create plug-ins yourself, or if you encounter an error, please let me know in the comments.
The result…
After registering the plug-in assembly and creating the plug-in step you can add them both to your solution and activate the plug-in step. When placing a mention on the timeline, a user will now receive the following notification:
Notes
To receive in-app notifications you need to enable “in-app notifications” per app.
If posts are not available on the timeline of an entity then you need to activate them, click here for more information.
Leave a Reply