Ejemplo n.º 1
0
        public void GetNotificationMessageBodyAsyncTestInvalidInput()
        {
            var notificationId = Guid.NewGuid().ToString();
            EmailNotificationItemEntity notificationItemEntity = new EmailNotificationItemEntity()
            {
                Application    = this.ApplicationName,
                NotificationId = notificationId,
                To             = "*****@*****.**",
                Subject        = "TestEmailSubject",
                TemplateData   = "lt7T9B6LY0XcfudckC73CepDKv/i84fJUKO9QsJzBpI=",
                TemplateId     = "Test Template",
                Id             = notificationId,
            };

            _ = Assert.ThrowsAsync <ArgumentNullException>(async() => await this.EmailManager.GetNotificationMessageBodyAsync(this.ApplicationName, (EmailNotificationItemEntity)null));
            _ = Assert.ThrowsAsync <ArgumentNullException>(async() => await this.EmailManager.GetNotificationMessageBodyAsync(null, notificationItemEntity));
        }
        /// <summary>
        /// Converts <see cref="EmailNotificationItemCosmosDbEntity"/> to a <see cref="EmailNotificationItemEntity"/>.
        /// </summary>
        /// <param name="emailNotificationItemDbEntity"> EmailNotificationItemCosmosDbEntity. </param>
        /// <returns><see cref="EmailNotificationItemEntity"/>.</returns>
        public static EmailNotificationItemEntity ConvertToEmailNotificationItemEntity(this EmailNotificationItemCosmosDbEntity emailNotificationItemDbEntity)
        {
            if (emailNotificationItemDbEntity is null)
            {
                return(null);
            }

            EmailNotificationItemEntity emailNotificationItemEntity = new EmailNotificationItemEntity();
            NotificationPriority        notificationPriority        = Enum.TryParse <NotificationPriority>(emailNotificationItemDbEntity.Priority, out notificationPriority) ? notificationPriority : NotificationPriority.Low;
            NotificationItemStatus      notificationItemStatus      = Enum.TryParse <NotificationItemStatus>(emailNotificationItemDbEntity.Status, out notificationItemStatus) ? notificationItemStatus : NotificationItemStatus.Queued;

            emailNotificationItemEntity.Priority         = notificationPriority;
            emailNotificationItemEntity.Status           = notificationItemStatus;
            emailNotificationItemEntity.PartitionKey     = emailNotificationItemDbEntity.Application;
            emailNotificationItemEntity.RowKey           = emailNotificationItemDbEntity.NotificationId;
            emailNotificationItemEntity.Application      = emailNotificationItemDbEntity.Application;
            emailNotificationItemEntity.BCC              = emailNotificationItemDbEntity.BCC;
            emailNotificationItemEntity.CC               = emailNotificationItemDbEntity.CC;
            emailNotificationItemEntity.EmailAccountUsed = emailNotificationItemDbEntity.EmailAccountUsed;
            emailNotificationItemEntity.ErrorMessage     = emailNotificationItemDbEntity.ErrorMessage;
            emailNotificationItemEntity.From             = emailNotificationItemDbEntity.From;
            emailNotificationItemEntity.NotificationId   = emailNotificationItemDbEntity.NotificationId;
            emailNotificationItemEntity.ReplyTo          = emailNotificationItemDbEntity.ReplyTo;
            emailNotificationItemEntity.Sensitivity      = emailNotificationItemDbEntity.Sensitivity;
            emailNotificationItemEntity.Subject          = emailNotificationItemDbEntity.Subject;
            emailNotificationItemEntity.TemplateId       = emailNotificationItemDbEntity.TemplateId;
            //emailNotificationItemEntity.TemplateData = emailNotificationItemDbEntity.TemplateData;
            emailNotificationItemEntity.Timestamp     = emailNotificationItemDbEntity.Timestamp;
            emailNotificationItemEntity.To            = emailNotificationItemDbEntity.To;
            emailNotificationItemEntity.TrackingId    = emailNotificationItemDbEntity.TrackingId;
            emailNotificationItemEntity.TryCount      = emailNotificationItemDbEntity.TryCount;
            emailNotificationItemEntity.ETag          = emailNotificationItemDbEntity.ETag;
            emailNotificationItemEntity.SendOnUtcDate = emailNotificationItemDbEntity.SendOnUtcDate;
            emailNotificationItemEntity.Id            = emailNotificationItemDbEntity.Id;
            return(emailNotificationItemEntity);
        }
Ejemplo n.º 3
0
        public void GetNotificationMessageBodyAsyncTestValidInput()
        {
            var notificationId = Guid.NewGuid().ToString();
            EmailNotificationItemEntity notificationItemEntity = new EmailNotificationItemEntity()
            {
                Application    = this.ApplicationName,
                NotificationId = notificationId,
                To             = "*****@*****.**",
                Subject        = "TestEmailSubject",
                TemplateData   = "lt7T9B6LY0XcfudckC73CepDKv/i84fJUKO9QsJzBpI=",
                TemplateId     = "Test Template",
                Id             = notificationId,
            };
            string mergedTemplate = "Testing Html template";

            var result = this.EmailManager.GetNotificationMessageBodyAsync(this.ApplicationName, notificationItemEntity);

            Assert.AreEqual(result.Status.ToString(), "RanToCompletion");
            Assert.AreEqual(result.Result.Content, mergedTemplate);

            this.TemplateManager.Verify(tmgr => tmgr.GetMailTemplate(It.IsAny <string>(), It.IsAny <string>()), Times.Once);
            this.TemplateMerge.Verify(tmr => tmr.CreateMailBodyUsingTemplate(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()), Times.Once);
            Assert.Pass();
        }
        /// <summary>
        /// Processes the notification items as a single batch to Graph.
        /// </summary>
        /// <param name="applicationName">The application Name.</param>
        /// <param name="notificationEntities">List of notification entities to process.</param>
        /// <param name="selectedAccount">selectedAccount.</param>
        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
        private async Task ProcessEntitiesInBatch(string applicationName, IList <EmailNotificationItemEntity> notificationEntities, Tuple <AuthenticationHeaderValue, AccountCredential> selectedAccount)
        {
            var traceProps = new Dictionary <string, string>();

            traceProps[AIConstants.Application]            = applicationName;
            traceProps["EmailAccountUsed"]                 = selectedAccount.Item2.AccountName.Base64Encode();
            traceProps[AIConstants.EmailNotificationCount] = notificationEntities.Count.ToString(CultureInfo.InvariantCulture);

            this.logger.TraceInformation($"Started {nameof(this.ProcessEntitiesInBatch)} method of {nameof(MSGraphNotificationProvider)}.", traceProps);
            if (notificationEntities is null || notificationEntities.Count == 0)
            {
                throw new ArgumentNullException(nameof(notificationEntities));
            }

            var sendForReal = this.mailSettings.Find(a => a.ApplicationName == applicationName).SendForReal;
            var toOverride  = this.mailSettings.Find(a => a.ApplicationName == applicationName).ToOverride;
            var saveToSent  = this.mailSettings.Find(a => a.ApplicationName == applicationName).SaveToSent;

            // Step 1: Prepare graph requests from input entities that shall be sent in a batch to Graph.
            List <GraphBatchRequest>             batchRequests      = new List <GraphBatchRequest>();
            List <GraphRequest>                  graphRequests      = new List <GraphRequest>();
            List <NotificationBatchItemResponse> batchItemResponses = new List <NotificationBatchItemResponse>();
            var nieItems = notificationEntities.ToList();

            foreach (var nie in nieItems)
            {
                EmailNotificationItemEntity item = nie;
                try
                {
                    MessageBody body = await this.emailManager.GetNotificationMessageBodyAsync(applicationName, item).ConfigureAwait(false);

                    EmailMessage message = nie.ToGraphEmailMessage(body);

                    if (!sendForReal)
                    {
                        this.logger.TraceInformation($"Overriding the ToRecipients in {nameof(this.ProcessEntitiesInBatch)} method of {nameof(EmailManager)}.", traceProps);
                        message.ToRecipients = toOverride.Split(Common.ApplicationConstants.SplitCharacter, System.StringSplitOptions.RemoveEmptyEntries)
                                               .Select(torecipient => new Recipient {
                            EmailAddress = new EmailAddress {
                                Address = torecipient
                            }
                        }).ToList();
                        message.CCRecipients      = null;
                        message.BCCRecipients     = null;
                        message.ReplyToRecipients = null;
                    }

                    graphRequests.Add(new GraphRequest()
                    {
                        Id   = nie.NotificationId,
                        Url  = this.mSGraphSetting.SendMailUrl.StartsWith("/", StringComparison.OrdinalIgnoreCase) ? this.mSGraphSetting.SendMailUrl : $"/{this.mSGraphSetting.SendMailUrl}",
                        Body = new EmailMessagePayload(message)
                        {
                            SaveToSentItems = saveToSent
                        },
                        Headers = new GraphRequestHeaders()
                        {
                            ContentType = ApplicationConstants.JsonMIMEType
                        },
                        Method = ApplicationConstants.POSTHttpVerb,
                    });
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    this.logger.TraceInformation($"Caught exception while creating the graph Message {nameof(this.ProcessEntitiesInBatch)} method of {nameof(MSGraphNotificationProvider)}.", traceProps);
                    batchItemResponses.Add(new NotificationBatchItemResponse {
                        Error = (ex.InnerException != null) ? ex.InnerException.Message : ex.Message, NotificationId = item.NotificationId, Status = HttpStatusCode.PreconditionFailed
                    });
                }
            }

            // Step 2: Split the full list of requests into smaller chunks as per the Graph Batch request limit.
            List <List <GraphRequest> > splitGraphRequests = BusinessUtilities.SplitList(graphRequests, this.mSGraphSetting.BatchRequestLimit).ToList();
            foreach (var graphRequestChunk in splitGraphRequests)
            {
                batchRequests.Add(new GraphBatchRequest()
                {
                    Requests = graphRequestChunk
                });
            }

            // Step 3: Invoke the Graph API for each batch request chunk prepared above.
            foreach (var batchRequest in batchRequests)
            {
                batchItemResponses.AddRange(await this.msGraphProvider.ProcessEmailRequestBatch(selectedAccount.Item1, batchRequest).ConfigureAwait(false));
            }

            bool isAccountIndexIncremented = false;

            // Step 4: Loop through the responses and set the status of the input entities.
            foreach (var item in notificationEntities)
            {
                item.EmailAccountUsed = selectedAccount.Item2.AccountName;
                item.TryCount++;
                item.ErrorMessage = string.Empty; // Reset the error message on next retry.
                var itemResponse = batchItemResponses.Find(resp => resp.NotificationId == item.NotificationId);
                if (itemResponse?.Status == HttpStatusCode.Accepted)
                {
                    item.Status = NotificationItemStatus.Sent;
                }
                else if (item.TryCount <= this.maxTryCount && (itemResponse?.Status == HttpStatusCode.TooManyRequests || itemResponse?.Status == HttpStatusCode.RequestTimeout))
                {
                    // Mark these items as queued and Queue them
                    item.Status               = NotificationItemStatus.Retrying;
                    item.ErrorMessage         = itemResponse?.Error;
                    isAccountIndexIncremented = this.IsMailboxLimitExchausted(itemResponse?.Error, item.NotificationId, item.EmailAccountUsed, isAccountIndexIncremented, traceProps);
                }
                else
                {
                    this.logger.WriteCustomEvent($"{AIConstants.CustomEventMailSendFailed} for notificationId:  {item.NotificationId} ");
                    item.Status       = NotificationItemStatus.Failed;
                    item.ErrorMessage = itemResponse?.Error;
                }
            }

            this.logger.TraceInformation($"Finished {nameof(this.ProcessEntitiesInBatch)} method of {nameof(MSGraphNotificationProvider)}.");
        }
Ejemplo n.º 5
0
        public void GetNotificationMessageTest()
        {
            Dictionary <string, string> testConfigValues = new Dictionary <string, string>()
            {
                { "RetrySetting:MaxRetries", "10" },
                { "RetrySetting:TransientRetryCount", "3" },
                { ConfigConstants.StorageType, StorageType.StorageAccount.ToString() },
            };

            this.Configuration = new ConfigurationBuilder()
                                 .AddInMemoryCollection(testConfigValues)
                                 .Build();

            EmailNotificationItemEntity notificationItemEntity = new EmailNotificationItemEntity()
            {
                Application = "TestApp",
                To          = "*****@*****.**",
                Subject     = "Test",
                Body        = "Test Body",
            };

            MessageBody body = new MessageBody
            {
                Content     = "Test Body",
                ContentType = "Text",
            };
            MailTemplate mailTemplate = new MailTemplate
            {
                Content      = "Test Body",
                Description  = "Test Description",
                TemplateId   = "TestTemplate-01",
                TemplateType = "Text",
            };
            string applicationName = "TestApp";
            string notificationId  = Guid.NewGuid().ToString();

            _ = this.EmailNotificationRepository
                .Setup(repository => repository.GetEmailNotificationItemEntity(notificationId, notificationItemEntity.Application))
                .ReturnsAsync(notificationItemEntity);

            _ = this.EmailNotificationRepositoryFactory
                .Setup(repository => repository.GetRepository(StorageType.StorageAccount))
                .Returns(this.EmailNotificationRepository.Object);

            _ = this.TemplateManager
                .Setup(c => c.GetMailTemplate(It.IsAny <string>(), It.IsAny <string>()))
                .ReturnsAsync(mailTemplate);

            _ = this.TemplateMerge
                .Setup(c => c.CreateMailBodyUsingTemplate(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
                .Returns("Test Message");

            this.NotificationReportManager = new NotificationReportManager(this.Logger, this.EmailNotificationRepositoryFactory.Object, this.Configuration, this.MailTemplateRepository.Object, this.TemplateManager.Object, this.TemplateMerge.Object);

            var managerResult = this.NotificationReportManager.GetNotificationMessage(applicationName, notificationId);

            Assert.AreEqual(managerResult.Status.ToString(), "RanToCompletion");
            Assert.AreEqual(managerResult.Result.Body.Content, body.Content);

            this.EmailNotificationRepositoryFactory.Verify(repo => repo.GetRepository(StorageType.StorageAccount).GetEmailNotificationItemEntity(notificationId, applicationName));
        }
        /// <summary>
        /// Get Notification Message Body Async.
        /// </summary>
        /// <param name="applicationName">Application sourcing the email notification.</param>
        /// <param name="notification">email notification item entity.</param>
        /// <returns>
        /// A <see cref="Task{TResult}" /> representing the result of the asynchronous operation.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// applicationName - applicationName cannot be null or empty.
        /// or
        /// notification - notification cannot be null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// TemplateData cannot be null or empty.
        /// or
        /// Template cannot be found, please provide a valid template and application name.
        /// </exception>
        public async Task <MessageBody> GetNotificationMessageBodyAsync(string applicationName, EmailNotificationItemEntity notification)
        {
            this.logger.TraceInformation($"Started {nameof(this.GetNotificationMessageBodyAsync)} method of {nameof(EmailManager)}.");
            string notificationBody = null;

            try
            {
                if (string.IsNullOrEmpty(applicationName))
                {
                    throw new ArgumentNullException(nameof(applicationName), "applicationName cannot be null or empty.");
                }

                if (notification is null)
                {
                    throw new ArgumentNullException(nameof(notification), "notification cannot be null.");
                }

                if (string.IsNullOrEmpty(notification.Body) && !string.IsNullOrEmpty(notification.TemplateId))
                {
                    if (string.IsNullOrEmpty(notification.TemplateData))
                    {
                        throw new ArgumentException("TemplateData cannot be null or empty.");
                    }

                    MailTemplate template = await this.templateManager.GetMailTemplate(applicationName, notification.TemplateId).ConfigureAwait(false);

                    if (template == null)
                    {
                        throw new ArgumentException("Template cannot be found, please provide a valid template and application name");
                    }

                    notificationBody = this.templateMerge.CreateMailBodyUsingTemplate(template.TemplateType, template.Content, notification.TemplateData);
                }
                else
                {
                    if (!string.IsNullOrEmpty(notification.Body))
                    {
                        notificationBody = notification.Body;
                    }
                }
            }
            catch (Exception ex)
            {
                this.logger.WriteException(ex);
                throw;
            }

            MessageBody messageBody = new MessageBody {
                Content = notificationBody, ContentType = Common.Constants.EmailBodyContentType
            };

            this.logger.TraceInformation($"Finished {nameof(this.GetNotificationMessageBodyAsync)} method of {nameof(EmailManager)}.");
            return(messageBody);
        }
        private EmailNotificationItemTableEntity ConvertToEmailNotificationItemTableEntity(EmailNotificationItemEntity emailNotificationItemEntity)
        {
            EmailNotificationItemTableEntity emailNotificationItemTableEntity = new EmailNotificationItemTableEntity();

            emailNotificationItemTableEntity.PartitionKey     = emailNotificationItemEntity.Application;
            emailNotificationItemTableEntity.RowKey           = emailNotificationItemEntity.NotificationId;
            emailNotificationItemTableEntity.Application      = emailNotificationItemEntity.Application;
            emailNotificationItemTableEntity.BCC              = emailNotificationItemEntity.BCC;
            emailNotificationItemTableEntity.CC               = emailNotificationItemEntity.CC;
            emailNotificationItemTableEntity.EmailAccountUsed = emailNotificationItemEntity.EmailAccountUsed;
            emailNotificationItemTableEntity.ErrorMessage     = emailNotificationItemEntity.ErrorMessage;
            emailNotificationItemTableEntity.Footer           = emailNotificationItemEntity.Footer;
            emailNotificationItemTableEntity.From             = emailNotificationItemEntity.From;
            emailNotificationItemTableEntity.Header           = emailNotificationItemEntity.Header;
            emailNotificationItemTableEntity.NotificationId   = emailNotificationItemEntity.NotificationId;
            emailNotificationItemTableEntity.Priority         = emailNotificationItemEntity.Priority.ToString();
            emailNotificationItemTableEntity.ReplyTo          = emailNotificationItemEntity.ReplyTo;
            emailNotificationItemTableEntity.Sensitivity      = emailNotificationItemEntity.Sensitivity;
            emailNotificationItemTableEntity.Status           = emailNotificationItemEntity.Status.ToString();
            emailNotificationItemTableEntity.Subject          = emailNotificationItemEntity.Subject;
            emailNotificationItemTableEntity.TemplateId       = emailNotificationItemEntity.TemplateId;
            emailNotificationItemTableEntity.Timestamp        = emailNotificationItemEntity.Timestamp;
            emailNotificationItemTableEntity.To               = emailNotificationItemEntity.To;
            emailNotificationItemTableEntity.TrackingId       = emailNotificationItemEntity.TrackingId;
            emailNotificationItemTableEntity.TryCount         = emailNotificationItemEntity.TryCount;
            emailNotificationItemTableEntity.ETag             = emailNotificationItemEntity.ETag;
            emailNotificationItemTableEntity.SendOnUtcDate    = emailNotificationItemEntity.SendOnUtcDate;
            return(emailNotificationItemTableEntity);
        }