From 069bc1e3097f1d82f58affbcafe6ab8b707e844b Mon Sep 17 00:00:00 2001 From: prodigygirl Date: Wed, 19 Apr 2023 15:42:26 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D0=B8?= =?UTF-8?q?=20=D0=B1=D0=B8=D0=B7=D0=BD=D0=B5=D1=81-=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=20=D0=BF=D0=BE=20=D0=BE=D1=82=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BA=D0=B5=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D1=8E=20=D0=BF=D0=B8=D1=81=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClientLogic.cs | 12 +++ .../FurnitureAssemblyBusinessLogic.csproj | 1 + .../MailWorker/AbstractMailWorker.cs | 81 +++++++++++++++++++ .../MailWorker/MailKitWorker.cs | 79 ++++++++++++++++++ .../OrderLogic.cs | 39 +++++++-- .../BindingModels/MailConfigBindingModel.cs | 13 +++ .../BindingModels/MailSendInfoBindingModel.cs | 9 +++ .../Implements/MessageInfoStorage.cs | 2 +- 8 files changed, 230 insertions(+), 6 deletions(-) create mode 100644 FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/AbstractMailWorker.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/MailKitWorker.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailConfigBindingModel.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailSendInfoBindingModel.cs diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/ClientLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/ClientLogic.cs index c5dd3b4..c790eef 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/ClientLogic.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/ClientLogic.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace FurnitureAssemblyBusinessLogic @@ -112,6 +113,17 @@ namespace FurnitureAssemblyBusinessLogic throw new ArgumentNullException("Нет пароля пользователя", nameof(model.Password)); } + + if (!Regex.IsMatch(model.Email, @"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,})+)$")) + { + throw new ArgumentException("Некорректно введена почта клиента", nameof(model.Email)); + } + if (!Regex.IsMatch(model.Password, @"^((\w+\d+\W+)|(\w+\W+\d+)|(\d+\w+\W+)|(\d+\W+\w+)|(\W+\w+\d+)|(\W+\d+\w+))[\w\d\W]*$")) + { + throw new ArgumentException("Некорректно введен пароль клиента", nameof(model.Password)); + } + + _logger.LogInformation("Component. ClientFIO:{ClientFIO}. Email:{ Email}. Id: { Id}", model.ClientFIO, model.Email, model.Id); var element = _clientStorage.GetElement(new ClientSearchModel { Email = model.Email }); if (element != null && element.Id != model.Id) diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/FurnitureAssemblyBusinessLogic.csproj b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/FurnitureAssemblyBusinessLogic.csproj index e811e1a..92c1d36 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/FurnitureAssemblyBusinessLogic.csproj +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/FurnitureAssemblyBusinessLogic.csproj @@ -8,6 +8,7 @@ + diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/AbstractMailWorker.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/AbstractMailWorker.cs new file mode 100644 index 0000000..4af8f1a --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/AbstractMailWorker.cs @@ -0,0 +1,81 @@ +using FurnitureAssemblyContracts.BindingModels; +using FurnitureAssemblyContracts.BusinessLogicsContarcts; +using Microsoft.Extensions.Logging; + +namespace FurnitureAssemblyBusinessLogic.MailWorker +{ + public abstract class AbstractMailWorker + { + protected string _mailLogin = string.Empty; + protected string _mailPassword = string.Empty; + protected string _smtpClientHost = string.Empty; + protected int _smtpClientPort; + protected string _popHost = string.Empty; + protected int _popPort; + private readonly IMessageInfoLogic _messageInfoLogic; + private readonly ILogger _logger; + private readonly IClientLogic _clientLogic; + public AbstractMailWorker(ILogger logger, + IMessageInfoLogic messageInfoLogic, + IClientLogic clientLogic) + { + _logger = logger; + _messageInfoLogic = messageInfoLogic; + _clientLogic = clientLogic; + } + public void MailConfig(MailConfigBindingModel config) + { + _mailLogin = config.MailLogin; + _mailPassword = config.MailPassword; + _smtpClientHost = config.SmtpClientHost; + _smtpClientPort = config.SmtpClientPort; + _popHost = config.PopHost; + _popPort = config.PopPort; + _logger.LogDebug("Config: {login}, {password}, {clientHost},{ clientPOrt}, { popHost}, { popPort}", _mailLogin, _mailPassword, _smtpClientHost, + _smtpClientPort, _popHost, _popPort); + } + public async void MailSendAsync(MailSendInfoBindingModel info) + { + if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword)) + { + return; + } + if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0) + { + return; + } + if (string.IsNullOrEmpty(info.MailAddress) || + string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Text)) + { + return; + } + _logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, + info.Subject); + await SendMailAsync(info); + } + public async void MailCheck() + { + if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword)) + { + return; + } + if (string.IsNullOrEmpty(_popHost) || _popPort == 0) + { + return; + } + if (_messageInfoLogic == null) + { + return; + } + var list = await ReceiveMailAsync(); + _logger.LogDebug("Check Mail: {Count} new mails", list.Count); + foreach (var mail in list) + { + mail.ClientId = _clientLogic.ReadElement(new() { Email = mail.SenderName })?.Id; + _messageInfoLogic.Create(mail); + } + } + protected abstract Task SendMailAsync(MailSendInfoBindingModel info); + protected abstract Task> ReceiveMailAsync(); + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/MailKitWorker.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/MailKitWorker.cs new file mode 100644 index 0000000..c7c5b51 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/MailWorker/MailKitWorker.cs @@ -0,0 +1,79 @@ +using FurnitureAssemblyContracts.BindingModels; +using FurnitureAssemblyContracts.BusinessLogicsContarcts; +using Microsoft.Extensions.Logging; +using System.Net.Mail; +using System.Net; +using System.Text; +using MailKit.Net.Pop3; +using MailKit.Security; + + +namespace FurnitureAssemblyBusinessLogic.MailWorker +{ + public class MailKitWorker : AbstractMailWorker + { + public MailKitWorker(ILogger logger, IMessageInfoLogic messageInfoLogic, IClientLogic clientLogic) : base(logger, messageInfoLogic, clientLogic) { } + protected override async Task SendMailAsync(MailSendInfoBindingModel + info) + { + using var objMailMessage = new MailMessage(); + using var objSmtpClient = new SmtpClient(_smtpClientHost,_smtpClientPort); + try + { + objMailMessage.From = new MailAddress(_mailLogin); + objMailMessage.To.Add(new MailAddress(info.MailAddress)); + objMailMessage.Subject = info.Subject; + objMailMessage.Body = info.Text; + objMailMessage.SubjectEncoding = Encoding.UTF8; + objMailMessage.BodyEncoding = Encoding.UTF8; + objSmtpClient.UseDefaultCredentials = false; + objSmtpClient.EnableSsl = true; + objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; + objSmtpClient.Credentials = new NetworkCredential(_mailLogin, + _mailPassword); + await Task.Run(() => objSmtpClient.Send(objMailMessage)); + } + catch (Exception) + { + throw; + } + } + protected override async Task> + ReceiveMailAsync() + { + var list = new List(); + using var client = new Pop3Client(); + await Task.Run(() => + { + try + { + client.Connect(_popHost, _popPort, SecureSocketOptions.SslOnConnect); + client.Authenticate(_mailLogin, _mailPassword); + for (int i = 0; i < client.Count; i++) + { + var message = client.GetMessage(i); + foreach (var mail in message.From.Mailboxes) + { + list.Add(new MessageInfoBindingModel + { + DateDelivery = message.Date.DateTime, + MessageId = message.MessageId, + SenderName = mail.Address, + Subject = message.Subject, + Body = message.TextBody + }); + } + } + } + catch (AuthenticationException) + { } + finally + { + client.Disconnect(true); + } + }); + return list; + } + + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OrderLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OrderLogic.cs index 36b3f18..350702b 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OrderLogic.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OrderLogic.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyContracts.BindingModels; +using FurnitureAssemblyBusinessLogic.MailWorker; +using FurnitureAssemblyContracts.BindingModels; using FurnitureAssemblyContracts.BusinessLogicsContarcts; using FurnitureAssemblyContracts.SearchModels; using FurnitureAssemblyContracts.StoragesContracts; @@ -17,11 +18,15 @@ namespace FurnitureAssemblyBusinessLogic { private readonly ILogger _logger; private readonly IOrderStorage _orderStorage; + private readonly AbstractMailWorker _mailWorker; + private readonly IClientLogic _clientLogic; - public OrderLogic(ILogger logger, IOrderStorage orderStorage) + public OrderLogic(ILogger logger, IOrderStorage orderStorage, IClientLogic clientLogic, AbstractMailWorker abstractMailWorker) { _logger = logger; _orderStorage = orderStorage; + _clientLogic = clientLogic; + _mailWorker = abstractMailWorker; } private bool ChangeStatus(OrderBindingModel model, OrderStatus orderStatus) @@ -31,6 +36,7 @@ namespace FurnitureAssemblyBusinessLogic return false; } model.Status = orderStatus; + SendMail(model.ClientId, $"Статус заказа {model.Id} изменен", $"Заказ {model.Id} переведен в статус {model.Status}"); return true; } @@ -43,13 +49,13 @@ namespace FurnitureAssemblyBusinessLogic _logger.LogWarning("Order's status is wrong"); throw new InvalidOperationException("Order's status is wrong"); } - - if (_orderStorage.Insert(model) == null) + var order = _orderStorage.Insert(model); + if (order == null) { _logger.LogWarning("Insert operation failed"); return false; } - + SendMail(model.ClientId, $"Создание заказа {order.Id}", $"Заказ под номером {order.Id} создан {model.DateCreate}"); return true; } @@ -61,6 +67,8 @@ namespace FurnitureAssemblyBusinessLogic return false; } model.Status = modelNew.Status; + model.ClientId = modelNew.ClientId; + model.Id = modelNew.Id; if (!ChangeStatus(model, OrderStatus.Выполняется)) { _logger.LogWarning("Order's status is wrong"); @@ -76,7 +84,9 @@ namespace FurnitureAssemblyBusinessLogic if (modelNew == null) { return false; } + model.Id = modelNew.Id; model.Status = modelNew.Status; + model.ClientId = modelNew.ClientId; model.ImplementerId = modelNew.ImplementerId; if (!ChangeStatus(model, OrderStatus.Готов)) { @@ -95,7 +105,9 @@ namespace FurnitureAssemblyBusinessLogic { return false; } + model.Id = modelNew.Id; model.Status = modelNew.Status; + model.ClientId = modelNew.ClientId; model.ImplementerId = modelNew.ImplementerId; model.DateImplement = modelNew.DateImplement; if (!ChangeStatus(model, OrderStatus.Выдан)) @@ -166,5 +178,22 @@ namespace FurnitureAssemblyBusinessLogic _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); return element; } + + private bool SendMail(int clientId, string subject, string text) + { + var client = _clientLogic.ReadElement(new() { Id = clientId}); + if (client == null) + { + _logger.LogWarning("Email sending failed. Client with id {Id} not found", clientId); + return false; + } + _mailWorker.MailSendAsync(new MailSendInfoBindingModel() + { + Subject = subject, + Text = text, + MailAddress = client.Email + }); + return true; + } } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailConfigBindingModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailConfigBindingModel.cs new file mode 100644 index 0000000..bdcc61e --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailConfigBindingModel.cs @@ -0,0 +1,13 @@ +namespace FurnitureAssemblyContracts.BindingModels +{ + public class MailConfigBindingModel + { + public string MailLogin { get; set; } = string.Empty; + public string MailPassword { get; set; } = string.Empty; + public string SmtpClientHost { get; set; } = string.Empty; + public int SmtpClientPort { get; set; } + public string PopHost { get; set; } = string.Empty; + public int PopPort { get; set; } + + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailSendInfoBindingModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailSendInfoBindingModel.cs new file mode 100644 index 0000000..90e7579 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MailSendInfoBindingModel.cs @@ -0,0 +1,9 @@ +namespace FurnitureAssemblyContracts.BindingModels +{ + public class MailSendInfoBindingModel + { + public string MailAddress { get; set; } = string.Empty; + public string Subject { get; set; } = string.Empty; + public string Text { get; set; } = string.Empty; + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/MessageInfoStorage.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/MessageInfoStorage.cs index e43736c..50468d4 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/MessageInfoStorage.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/MessageInfoStorage.cs @@ -30,7 +30,7 @@ namespace FurnitureAssemblyDatabaseImplement.Implements } using var context = new FurnitureAssemblyDatabase(); return context.Messages - .Where(x => x.ClientId.Equals(model.ClientId)) + .Where(x => x.ClientId == model.ClientId) .Select(x => x.GetViewModel) .ToList(); }