private void HandleNonCustomAction(IPluginExecutionContext context, ITracingService tracing, IOrganizationService service)
        {
            var target = context.InputParameters.ContainsKey("Target") ? context.InputParameters["Target"] as Entity : null;

            if (target == null)
            {
                return;
            }

            var targetField   = _config.TargetField;
            var template      = _config.Template;
            var templateField = _config.TemplateField;

            var dataSource = GenerateDataSource(context, target);

            if (!CheckExecutionCriteria(_config, dataSource, service, tracing))
            {
                tracing.Trace("Execution criteria not met, aborting");
                return;
            }

            ValidateConfig(targetField, template, templateField);
            var templateText = RetrieveTemplate(template, templateField, dataSource, service, tracing);

            if (string.IsNullOrEmpty(templateText))
            {
                tracing.Trace("Template is empty, aborting");
                return;
            }

            var output = TokenMatcher.ProcessTokens(templateText, dataSource, _organizationConfig, service, tracing);

            target[targetField] = output;
            TriggerUpdateConditionally(output, dataSource, _config, service);
        }
        public void Execute(IServiceProvider serviceProvider)
        {
            var context        = serviceProvider.GetService(typeof(IPluginExecutionContext)) as IPluginExecutionContext;
            var crmTracing     = serviceProvider.GetService(typeof(ITracingService)) as ITracingService;
            var serviceFactory = serviceProvider.GetService(typeof(IOrganizationServiceFactory)) as IOrganizationServiceFactory;
            var service        = serviceFactory.CreateOrganizationService(context.UserId);

            var target    = GetTarget(context);
            var targetRef = GetTargetRef(context);

            if (target == null && targetRef == null)
            {
                return;
            }

            var shouldExecute = CheckExecutionCondition(target, service, crmTracing);

            if (!shouldExecute)
            {
                crmTracing.Trace("Execution condition not met, aborting");
                return;
            }

            var attributes = target != null
                ? target.Attributes.Keys.ToList()
                : null;

            var filteredAttributes = config.Value.CapturedFields != null
                ? attributes.Where(a => config.Value.CapturedFields.Any(f => string.Equals(a, f, StringComparison.InvariantCultureIgnoreCase))).ToList()
                : attributes;

            var eventData = new EventData
            {
                UpdatedFields        = filteredAttributes,
                EventRecordReference = target?.ToEntityReference() ?? targetRef
            };

            var eventTarget = string.IsNullOrEmpty(config.Value.ParentLookupName) && eventData.EventRecordReference.Id != Guid.Empty
                ? eventData.EventRecordReference
                : GetValue <EntityReference>(config.Value.ParentLookupName, target, context.PreEntityImages);

            if (eventTarget == null)
            {
                crmTracing.Trace("Failed to find parent, exiting");
                return;
            }

            var subscriptionsQuery = service.Query("oss_subscription")
                                     .Where(e => e
                                            .Attribute(a => a
                                                       .Named(config.Value.SubscriptionLookupName)
                                                       .Is(ConditionOperator.Equal)
                                                       .To(eventTarget.Id)
                                                       )
                                            .Attribute(a => a
                                                       .Named("statecode")
                                                       .Is(ConditionOperator.Equal)
                                                       .To(0)
                                                       )
                                            )
                                     .IncludeColumns("ownerid", "oss_emailnotificationsenabled", "oss_emailnotificationssender")
                                     .Link(l => l
                                           .FromEntity("oss_subscription")
                                           .ToEntity("systemuser")
                                           .FromAttribute("ownerid")
                                           .ToAttribute("systemuserid")
                                           .With.LinkType(JoinOperator.LeftOuter)
                                           .Link(l2 => l2
                                                 .FromEntity("systemuser")
                                                 .ToEntity("usersettings")
                                                 .FromAttribute("systemuserid")
                                                 .ToAttribute("systemuserid")
                                                 .With.LinkType(JoinOperator.LeftOuter)
                                                 .With.Alias("usersettings")
                                                 .IncludeColumns("localeid")
                                                 )
                                           );

            if (!config.Value.NotifyCurrentUser)
            {
                subscriptionsQuery.AddCondition(
                    (a => a
                     .Named("ownerid")
                     .Is(ConditionOperator.NotEqual)
                     .To(context.UserId)
                    )
                    );
            }

            var subscriptions = subscriptionsQuery.RetrieveAll();

            var serializedNotification = JsonSerializer.Serialize(eventData);
            var eventType = GetEventType(context);

            var messageConfig = config.Value.MessageConfig ?? new Dictionary <string, string>();

            var messages = subscriptions.Select(s => s.GetAttributeValue <AliasedValue>("usersettings.localeid")?.Value as int?)
                           .Select(locale => locale != null ? locale.Value.ToString() : "default")
                           .Distinct()
                           .ToDictionary(
                (k) => k,
                (k) => messageConfig.ContainsKey(k)
                        ? TokenMatcher.ProcessTokens(messageConfig[k], target, new OrganizationConfig(), service, crmTracing)
                        : (messageConfig.ContainsKey("default") ? TokenMatcher.ProcessTokens(messageConfig["default"], target, new OrganizationConfig(), service, crmTracing) : null)
                );

            subscriptions.ForEach(subscription =>
            {
                var localeCode = subscription.GetAttributeValue <AliasedValue>("usersettings.localeid")?.Value as int?;
                var locale     = localeCode != null ? localeCode.Value.ToString() : "default";

                var message = messages.ContainsKey(locale) ? messages[locale] : null;
                var user    = subscription.GetAttributeValue <EntityReference>("ownerid");

                var notification = new Entity
                {
                    LogicalName = "oss_notification",
                    Attributes  =
                    {
                        ["oss_subscriptionid"] = subscription.ToEntityReference(),
                        ["ownerid"]            = user,
                        ["oss_event"]          = new OptionSetValue((int)eventType),
                        [config.Value.NotificationLookupName] = eventTarget,
                        ["oss_data"] = serializedNotification,
                        ["oss_text"] = message
                    }
                };

                if (config.Value.GlobalNotificationConfig != null)
                {
                    var messageKey = config.Value.GlobalNotificationConfig.Keys.FirstOrDefault(k => k == locale) ?? config.Value.GlobalNotificationConfig.Keys.FirstOrDefault(k => k == "default");

                    if (messageKey != null)
                    {
                        var notificationMessage = config.Value.GlobalNotificationConfig[messageKey];

                        var payload = new GlobalNotificationActionPayload
                        {
                            EntityName = eventTarget?.LogicalName,
                            Message    = notificationMessage
                        };

                        notification["oss_globalnotificationactionpayload"] = JsonSerializer.Serialize(payload);
                    }
                }

                notification.Id = service.Create(notification);

                var emailNotificationsEnabled = subscription.GetAttributeValue <bool>("oss_emailnotificationsenabled");

                if (!emailNotificationsEnabled)
                {
                    return;
                }

                SendEmailNotification(message, locale, user, subscription, notification, service);
            });
        }
        private void HandleCustomAction(IPluginExecutionContext context, PersistentTracingService tracing, IOrganizationService service)
        {
            var config = ProcessorConfig.Parse(context.InputParameters["jsonInput"] as string);

            if (config.Target == null && config.TargetEntity == null)
            {
                throw new InvalidPluginExecutionException("Target property inside JSON parameters is needed for custom actions");
            }

            ColumnSet columnSet;

            if (config.TargetColumns != null)
            {
                columnSet = new ColumnSet(config.TargetColumns);
            }
            else
            {
                columnSet = new ColumnSet(true);
            }

            try
            {
                var dataSource = config.TargetEntity != null ? config.TargetEntity : service.Retrieve(config.Target.LogicalName, config.Target.Id, columnSet);

                if (!CheckExecutionCriteria(config, dataSource, service, tracing))
                {
                    tracing.Trace("Execution criteria not met, aborting");

                    var abortResult = new ProcessingResult
                    {
                        Success  = true,
                        Result   = config.Template,
                        TraceLog = tracing.TraceLog
                    };
                    context.OutputParameters["jsonOutput"] = SerializeResult(abortResult);

                    return;
                }

                var templateText = RetrieveTemplate(config.Template, config.TemplateField, dataSource, service, tracing);

                if (string.IsNullOrEmpty(templateText))
                {
                    tracing.Trace("Template is empty, aborting");
                    return;
                }

                var output = TokenMatcher.ProcessTokens(templateText, dataSource, new OrganizationConfig {
                    OrganizationUrl = config.OrganizationUrl
                }, service, tracing);

                var result = new ProcessingResult
                {
                    Success  = true,
                    Result   = output,
                    TraceLog = tracing.TraceLog
                };
                context.OutputParameters["jsonOutput"] = SerializeResult(result);

                TriggerUpdateConditionally(output, dataSource, config, service);
            }
            catch (Exception ex)
            {
                var result = new ProcessingResult
                {
                    Success  = false,
                    Error    = ex.Message,
                    TraceLog = tracing.TraceLog
                };
                context.OutputParameters["jsonOutput"] = SerializeResult(result);

                if (config.ThrowOnCustomActionError)
                {
                    throw;
                }
            }
        }