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); }
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)}."); }
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); }