From f4154069116cdb372d435aec80ef8602de1fe731 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Tue, 9 Jan 2024 16:43:39 +0500 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3=20WorkToSendEmail,=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=BD=D0=BE=D1=81=20=D1=81=D0=BE=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B8=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=B8=D0=B7=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20Action=20=D0=B2=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=B4=20SendAsync=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=20EmailNotificationTransportService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Background/WorkToSendEmail.cs | 65 +-------------- .../EmailNotificationTransportService.cs | 81 +++++++++++++++---- 2 files changed, 69 insertions(+), 77 deletions(-) diff --git a/AsbCloudInfrastructure/Background/WorkToSendEmail.cs b/AsbCloudInfrastructure/Background/WorkToSendEmail.cs index 96136cde..c766c5b0 100644 --- a/AsbCloudInfrastructure/Background/WorkToSendEmail.cs +++ b/AsbCloudInfrastructure/Background/WorkToSendEmail.cs @@ -1,11 +1,7 @@ using AsbCloudApp.Data; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Repositories; -using Microsoft.Extensions.Configuration; +using AsbCloudApp.Services.Notifications; using Microsoft.Extensions.DependencyInjection; using System; -using System.Diagnostics; -using System.Net.Mail; using System.Threading; using System.Threading.Tasks; @@ -17,69 +13,16 @@ namespace AsbCloudInfrastructure.Background internal class WorkToSendEmail : Work { private NotificationDto notification; - private string sender; - private string smtpPassword; - private string smtpServer; - private bool IsConfigured; - public WorkToSendEmail(NotificationDto notification, IConfiguration configuration) : base(MakeWorkId(notification)) + public WorkToSendEmail(NotificationDto notification) : base(MakeWorkId(notification)) { this.notification = notification; - - sender = configuration.GetValue("email:sender", string.Empty); - smtpPassword = configuration.GetValue("email:password", string.Empty); - smtpServer = configuration.GetValue("email:smtpServer", string.Empty); - - var configError = string.IsNullOrEmpty(sender) || - string.IsNullOrEmpty(smtpPassword) || - string.IsNullOrEmpty(smtpServer); - - IsConfigured = !configError; } - protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { - if (!IsConfigured) - { - Trace.TraceWarning("smtp is not configured"); - return; - } - - var notificationRepository = services.GetRequiredService(); - var userRepository = services.GetRequiredService(); - - var user = await userRepository.GetOrDefaultAsync(notification.IdUser, token) - ?? throw new ArgumentInvalidException(nameof(notification.IdUser), "Пользователь не найден"); - - if (!MailAddress.TryCreate(user.Email, out var mailAddress)) - { - Trace.TraceWarning($"Mail {user.Email} is not correct."); - throw new ArgumentInvalidException(nameof(user.Email), $"Mail {user.Email} is not null."); - } - - var from = new MailAddress(sender); - var message = new MailMessage - { - From = from - }; - - message.To.Add(mailAddress.Address); - message.BodyEncoding = System.Text.Encoding.UTF8; - message.Body = notification.Message; - message.Subject = notification.Title; - message.IsBodyHtml = true; - - using var client = new SmtpClient(smtpServer); - client.EnableSsl = true; - client.UseDefaultCredentials = false; - client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword); - - await client.SendMailAsync(message, token); - notification.SentDate = DateTime.UtcNow; - await notificationRepository.UpdateAsync(notification, token); - - Trace.TraceInformation($"Send email to {user.Email} subj:{notification.Title} html body count {notification.Message.Length}"); + var notificationService = services.GetRequiredService(); + await notificationService.SendAsync(notification, token); } diff --git a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs index f41bd7ad..a0f9e208 100644 --- a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs +++ b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs @@ -1,9 +1,14 @@ using AsbCloudApp.Data; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; using AsbCloudApp.Services.Notifications; using AsbCloudInfrastructure.Background; using Microsoft.Extensions.Configuration; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Net.Mail; using System.Threading; using System.Threading.Tasks; @@ -12,27 +17,73 @@ namespace AsbCloudInfrastructure.Services.Email public class EmailNotificationTransportService : INotificationTransportService { - private readonly IConfiguration configuration; - private readonly BackgroundWorker backgroundWorker; - - public EmailNotificationTransportService(BackgroundWorker backgroundWorker, - IConfiguration configuration) - { - this.configuration = configuration; - this.backgroundWorker = backgroundWorker; - } + private readonly INotificationRepository notificationRepository; + private readonly IUserRepository userRepository; + private readonly string sender; + private readonly string smtpPassword; + private readonly string smtpServer; public int IdTransportType => 1; + public bool IsConfigured { get; } - public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken) + public EmailNotificationTransportService(BackgroundWorker backgroundWorker, + IConfiguration configuration, + INotificationRepository notificationRepository, + IUserRepository userRepository) { - var work = new WorkToSendEmail(notification, configuration); - if (!backgroundWorker.Works.Any(w => w.Id == work.Id)) + this.notificationRepository = notificationRepository; + this.userRepository = userRepository; + + this.sender = configuration.GetValue("email:sender", string.Empty); + this.smtpPassword = configuration.GetValue("email:password", string.Empty); + this.smtpServer = configuration.GetValue("email:smtpServer", string.Empty); + + var configError = string.IsNullOrEmpty(this.sender) || + string.IsNullOrEmpty(this.smtpPassword) || + string.IsNullOrEmpty(this.smtpServer); + + this.IsConfigured = !configError; + } + + public async Task SendAsync(NotificationDto notification, CancellationToken token) + { + if (!IsConfigured) { - backgroundWorker.Enqueue(work); + Trace.TraceWarning("smtp is not configured"); + return; } - return Task.CompletedTask; + var user = await userRepository.GetOrDefaultAsync(notification.IdUser, token) + ?? throw new ArgumentInvalidException(nameof(notification.IdUser), "Пользователь не найден"); + + if (!MailAddress.TryCreate(user.Email, out var mailAddress)) + { + Trace.TraceWarning($"Mail {user.Email} is not correct."); + throw new ArgumentInvalidException(nameof(user.Email), $"Mail {user.Email} is not null."); + } + + var from = new MailAddress(sender); + var message = new MailMessage + { + From = from + }; + + message.To.Add(mailAddress.Address); + message.BodyEncoding = System.Text.Encoding.UTF8; + message.Body = notification.Message; + message.Subject = notification.Title; + message.IsBodyHtml = true; + + using var client = new SmtpClient(smtpServer); + client.EnableSsl = true; + client.UseDefaultCredentials = false; + client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword); + + await client.SendMailAsync(message, token); + notification.SentDate = DateTime.UtcNow; + await notificationRepository.UpdateAsync(notification, token); + + Trace.TraceInformation($"Send email to {user.Email} subj:{notification.Title} html body count {notification.Message.Length}"); } public Task SendRangeAsync(IEnumerable notifications, CancellationToken cancellationToken) @@ -42,7 +93,5 @@ namespace AsbCloudInfrastructure.Services.Email return Task.WhenAll(tasks); } - - } } From 67481a7743bd6e29c3e87e00ab6f3684cea1aa49 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 10 Jan 2024 14:17:21 +0500 Subject: [PATCH 2/3] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B=20+=20=D0=BA=D0=BE=D0=B4=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20notification=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=83=D1=80=D0=BE=D0=B2=D0=B5=D0=BD=D1=8C=20=D0=B2=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Notifications/NotificationService.cs | 11 +++ .../Background/WorkToSendEmail.cs | 7 ++ .../EmailNotificationTransportService.cs | 7 +- .../EmailNotificationTransportServiceTests.cs | 78 +++++++++++++++++++ 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs diff --git a/AsbCloudApp/Services/Notifications/NotificationService.cs b/AsbCloudApp/Services/Notifications/NotificationService.cs index 4537f04e..d0414213 100644 --- a/AsbCloudApp/Services/Notifications/NotificationService.cs +++ b/AsbCloudApp/Services/Notifications/NotificationService.cs @@ -61,6 +61,9 @@ public class NotificationService var notificationTransportService = GetTransportService(request.IdTransportType); await notificationTransportService.SendAsync(notification, cancellationToken); + + notification.SentDate = DateTime.UtcNow; + await notificationRepository.UpdateAsync(notification, cancellationToken); } /// @@ -104,6 +107,14 @@ public class NotificationService await notificationTransportService.SendRangeAsync(notifications, cancellationToken); + + var tasks = notifications.Select(notification => + { + notification.SentDate = DateTime.UtcNow; + return notificationRepository.UpdateAsync(notification, cancellationToken); + }); + + await Task.WhenAll(tasks); } private INotificationTransportService GetTransportService(int idTransportType) diff --git a/AsbCloudInfrastructure/Background/WorkToSendEmail.cs b/AsbCloudInfrastructure/Background/WorkToSendEmail.cs index c766c5b0..57605438 100644 --- a/AsbCloudInfrastructure/Background/WorkToSendEmail.cs +++ b/AsbCloudInfrastructure/Background/WorkToSendEmail.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Repositories; using AsbCloudApp.Services.Notifications; using Microsoft.Extensions.DependencyInjection; using System; @@ -22,7 +23,13 @@ namespace AsbCloudInfrastructure.Background protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { var notificationService = services.GetRequiredService(); + var notificationRepository = services.GetRequiredService(); + await notificationService.SendAsync(notification, token); + + notification.SentDate = DateTime.UtcNow; + await notificationRepository.UpdateAsync(notification, token); + } diff --git a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs index a0f9e208..9ff3961f 100644 --- a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs +++ b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs @@ -17,7 +17,6 @@ namespace AsbCloudInfrastructure.Services.Email public class EmailNotificationTransportService : INotificationTransportService { - private readonly INotificationRepository notificationRepository; private readonly IUserRepository userRepository; private readonly string sender; private readonly string smtpPassword; @@ -26,12 +25,10 @@ namespace AsbCloudInfrastructure.Services.Email public int IdTransportType => 1; public bool IsConfigured { get; } - public EmailNotificationTransportService(BackgroundWorker backgroundWorker, + public EmailNotificationTransportService( IConfiguration configuration, - INotificationRepository notificationRepository, IUserRepository userRepository) { - this.notificationRepository = notificationRepository; this.userRepository = userRepository; this.sender = configuration.GetValue("email:sender", string.Empty); @@ -80,8 +77,6 @@ namespace AsbCloudInfrastructure.Services.Email client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword); await client.SendMailAsync(message, token); - notification.SentDate = DateTime.UtcNow; - await notificationRepository.UpdateAsync(notification, token); Trace.TraceInformation($"Send email to {user.Email} subj:{notification.Title} html body count {notification.Message.Length}"); } diff --git a/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs b/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs new file mode 100644 index 00000000..696f4060 --- /dev/null +++ b/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs @@ -0,0 +1,78 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.User; +using AsbCloudApp.Repositories; +using AsbCloudApp.Services.Notifications; +using AsbCloudInfrastructure.Services.Email; +using Microsoft.Extensions.Configuration; +using NSubstitute; +using System; +using System.Collections.Generic; +using System.Net.Mail; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace AsbCloudWebApi.Tests.UnitTests.Services.Notification +{ + public class EmailNotificationTransportServiceTests + { + private IUserRepository userRepository; + private INotificationTransportService notificationTransportService; + + private readonly NotificationDto notification = new NotificationDto() + { + Message = "Message", + Title = "Title", + IdUser = 1, + IdTransportType = 1, + IdState = 0, + RegistrationDate = DateTime.Now, + IdNotificationCategory = 10000, + }; + private readonly UserExtendedDto user = new UserExtendedDto() + { + Id = 1, + IdCompany = 1, + Email = "studio@yandex.ru", + IdState = 1, + Login = "studio", + Name = "Test", + Patronymic = "Test", + Phone = "22-22-22", + Position = "Test", + Surname = "Test", + }; + + private static Dictionary configSettings = new() + { + { "email:sender", "bot@digitaldrilling.ru" }, + { "email:password", "8wZrXSfP" }, + { "email:smtpServer", "smtp.timeweb.ru" } + }; + + public EmailNotificationTransportServiceTests() + { + IConfiguration configuration = new ConfigurationBuilder() + .AddInMemoryCollection(configSettings) + .Build(); + + userRepository = Substitute.For(); + + notificationTransportService = new EmailNotificationTransportService(configuration, userRepository); + } + + [Fact] + public async Task SendAsync() + { + userRepository.GetOrDefaultAsync(Arg.Any(), Arg.Any()).Returns(user); + try + { + await notificationTransportService.SendAsync(notification, CancellationToken.None); + } + catch (Exception e) + { + Assert.True(e is SmtpException); + } + } + } +} From c2f69463d2719bce629f037cef3e851aaaec78db Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Wed, 10 Jan 2024 17:57:58 +0500 Subject: [PATCH 3/3] Fix EmailNotificationTransportServiceTests --- .../Email/EmailNotificationTransportService.cs | 2 -- .../EmailNotificationTransportServiceTests.cs | 12 +++--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs index 9ff3961f..2eec7b27 100644 --- a/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs +++ b/AsbCloudInfrastructure/Services/Email/EmailNotificationTransportService.cs @@ -2,9 +2,7 @@ using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Services.Notifications; -using AsbCloudInfrastructure.Background; using Microsoft.Extensions.Configuration; -using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; diff --git a/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs b/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs index 696f4060..c3dc936a 100644 --- a/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs +++ b/AsbCloudWebApi.Tests/UnitTests/Services/Notification/EmailNotificationTransportServiceTests.cs @@ -62,17 +62,11 @@ namespace AsbCloudWebApi.Tests.UnitTests.Services.Notification } [Fact] - public async Task SendAsync() + public async Task SendAsyncThrowsMailboxUnavailable() { userRepository.GetOrDefaultAsync(Arg.Any(), Arg.Any()).Returns(user); - try - { - await notificationTransportService.SendAsync(notification, CancellationToken.None); - } - catch (Exception e) - { - Assert.True(e is SmtpException); - } + var exception = await Assert.ThrowsAsync(() => notificationTransportService.SendAsync(notification, CancellationToken.None)); + Assert.Equal(SmtpStatusCode.MailboxUnavailable, exception.StatusCode); } } }