Press ESC to close

Arjan ter HeegdeArjan ter Heegde Welcome to my blog about Microsoft Power Platform and Dynamics 365

Notify users if they are mentioned in a post

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.

Arjan ter Heegde

Arjan ter Heegde

Leave a Reply

Your email address will not be published. Required fields are marked *