diff --git a/TravelCompany/TravelCompany/App.config b/TravelCompany/TravelCompany/App.config new file mode 100644 index 0000000..c1caed3 --- /dev/null +++ b/TravelCompany/TravelCompany/App.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/TravelCompany/TravelCompany/FormMail.Designer.cs b/TravelCompany/TravelCompany/FormMail.Designer.cs new file mode 100644 index 0000000..98ccc14 --- /dev/null +++ b/TravelCompany/TravelCompany/FormMail.Designer.cs @@ -0,0 +1,69 @@ +namespace TravelCompany +{ + partial class FormMail + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.dataGridView = new System.Windows.Forms.DataGridView(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit(); + this.SuspendLayout(); + // + // dataGridView + // + this.dataGridView.BackgroundColor = System.Drawing.Color.White; + this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView.Dock = System.Windows.Forms.DockStyle.Fill; + this.dataGridView.Location = new System.Drawing.Point(0, 0); + this.dataGridView.Margin = new System.Windows.Forms.Padding(2); + this.dataGridView.MultiSelect = false; + this.dataGridView.Name = "dataGridView"; + this.dataGridView.RowHeadersVisible = false; + this.dataGridView.RowHeadersWidth = 62; + this.dataGridView.RowTemplate.Height = 33; + this.dataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dataGridView.Size = new System.Drawing.Size(800, 450); + this.dataGridView.TabIndex = 6; + // + // FormMail + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.dataGridView); + this.Name = "FormMail"; + this.Text = "Почта"; + this.Load += new System.EventHandler(this.FormMail_Load); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private DataGridView dataGridView; + } +} \ No newline at end of file diff --git a/TravelCompany/TravelCompany/FormMail.cs b/TravelCompany/TravelCompany/FormMail.cs new file mode 100644 index 0000000..cf50384 --- /dev/null +++ b/TravelCompany/TravelCompany/FormMail.cs @@ -0,0 +1,47 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using TravelCompanyContracts.BusinessLogicsContracts; + +namespace TravelCompany +{ + public partial class FormMail : Form + { + private readonly ILogger _logger; + private readonly IMessageInfoLogic _logic; + public FormMail(ILogger logger, IMessageInfoLogic logic) + { + InitializeComponent(); + _logger = logger; + _logic = logic; + } + + private void FormMail_Load(object sender, EventArgs e) + { + try + { + var list = _logic.ReadList(null); + if (list != null) + { + dataGridView.DataSource = list; + dataGridView.Columns["MessageId"].Visible = false; + dataGridView.Columns["ClientId"].Visible = false; + dataGridView.Columns["Body"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; + } + _logger.LogInformation("Загрузка писем"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка загрузки писем"); + MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} diff --git a/TravelCompany/TravelCompany/FormMail.resx b/TravelCompany/TravelCompany/FormMail.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/TravelCompany/TravelCompany/FormMail.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/TravelCompany/TravelCompany/FormMain.Designer.cs b/TravelCompany/TravelCompany/FormMain.Designer.cs index b697091..0e0bc37 100644 --- a/TravelCompany/TravelCompany/FormMain.Designer.cs +++ b/TravelCompany/TravelCompany/FormMain.Designer.cs @@ -34,6 +34,7 @@ this.условияToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.путешествияToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.клиентыToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.исполнителиToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.отчетToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.списокУсловийToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.условияПоПоездкамToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -44,7 +45,7 @@ this.ButtonOrderReady = new System.Windows.Forms.Button(); this.ButtonIssuedOrder = new System.Windows.Forms.Button(); this.ButtonRef = new System.Windows.Forms.Button(); - this.исполнителиToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.почтаToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit(); this.menuStrip.SuspendLayout(); this.SuspendLayout(); @@ -70,7 +71,8 @@ this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.справочникиToolStripMenuItem, this.отчетToolStripMenuItem, - this.запускРаботToolStripMenuItem}); + this.запускРаботToolStripMenuItem, + this.почтаToolStripMenuItem}); this.menuStrip.Location = new System.Drawing.Point(0, 0); this.menuStrip.Name = "menuStrip"; this.menuStrip.Padding = new System.Windows.Forms.Padding(5, 2, 0, 2); @@ -92,24 +94,31 @@ // условияToolStripMenuItem // this.условияToolStripMenuItem.Name = "условияToolStripMenuItem"; - this.условияToolStripMenuItem.Size = new System.Drawing.Size(224, 26); + this.условияToolStripMenuItem.Size = new System.Drawing.Size(185, 26); this.условияToolStripMenuItem.Text = "Условия"; this.условияToolStripMenuItem.Click += new System.EventHandler(this.условияToolStripMenuItem_Click); // // путешествияToolStripMenuItem // this.путешествияToolStripMenuItem.Name = "путешествияToolStripMenuItem"; - this.путешествияToolStripMenuItem.Size = new System.Drawing.Size(224, 26); + this.путешествияToolStripMenuItem.Size = new System.Drawing.Size(185, 26); this.путешествияToolStripMenuItem.Text = "Путешествия"; this.путешествияToolStripMenuItem.Click += new System.EventHandler(this.путешествияToolStripMenuItem_Click); // // клиентыToolStripMenuItem // this.клиентыToolStripMenuItem.Name = "клиентыToolStripMenuItem"; - this.клиентыToolStripMenuItem.Size = new System.Drawing.Size(224, 26); + this.клиентыToolStripMenuItem.Size = new System.Drawing.Size(185, 26); this.клиентыToolStripMenuItem.Text = "Клиенты"; this.клиентыToolStripMenuItem.Click += new System.EventHandler(this.клиентыToolStripMenuItem_Click); // + // исполнителиToolStripMenuItem + // + this.исполнителиToolStripMenuItem.Name = "исполнителиToolStripMenuItem"; + this.исполнителиToolStripMenuItem.Size = new System.Drawing.Size(185, 26); + this.исполнителиToolStripMenuItem.Text = "Исполнители"; + this.исполнителиToolStripMenuItem.Click += new System.EventHandler(this.исполнителиToolStripMenuItem_Click); + // // отчетToolStripMenuItem // this.отчетToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -203,12 +212,12 @@ this.ButtonRef.UseVisualStyleBackColor = true; this.ButtonRef.Click += new System.EventHandler(this.ButtonRef_Click); // - // исполнителиToolStripMenuItem + // почтаToolStripMenuItem // - this.исполнителиToolStripMenuItem.Name = "исполнителиToolStripMenuItem"; - this.исполнителиToolStripMenuItem.Size = new System.Drawing.Size(224, 26); - this.исполнителиToolStripMenuItem.Text = "Исполнители"; - this.исполнителиToolStripMenuItem.Click += new System.EventHandler(this.исполнителиToolStripMenuItem_Click); + this.почтаToolStripMenuItem.Name = "почтаToolStripMenuItem"; + this.почтаToolStripMenuItem.Size = new System.Drawing.Size(65, 24); + this.почтаToolStripMenuItem.Text = "Почта"; + this.почтаToolStripMenuItem.Click += new System.EventHandler(this.почтаToolStripMenuItem_Click); // // FormMain // @@ -254,5 +263,6 @@ private ToolStripMenuItem клиентыToolStripMenuItem; private ToolStripMenuItem запускРаботToolStripMenuItem; private ToolStripMenuItem исполнителиToolStripMenuItem; + private ToolStripMenuItem почтаToolStripMenuItem; } } \ No newline at end of file diff --git a/TravelCompany/TravelCompany/FormMain.cs b/TravelCompany/TravelCompany/FormMain.cs index 344260a..370ea1c 100644 --- a/TravelCompany/TravelCompany/FormMain.cs +++ b/TravelCompany/TravelCompany/FormMain.cs @@ -36,8 +36,9 @@ namespace TravelCompany dataGridView.Columns["TravelId"].Visible = false; dataGridView.Columns["ClientId"].Visible = false; dataGridView.Columns["ImplementerId"].Visible = false; + dataGridView.Columns["ClientEmail"].Visible = false; dataGridView.Columns["TravelName"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - dataGridView.Columns["ClientFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; + dataGridView.Columns["ClientFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; } } catch (Exception ex) @@ -208,5 +209,14 @@ namespace TravelCompany form.ShowDialog(); } } + + private void почтаToolStripMenuItem_Click(object sender, EventArgs e) + { + var service = Program.ServiceProvider?.GetService(typeof(FormMail)); + if (service is FormMail form) + { + form.ShowDialog(); + } + } } } diff --git a/TravelCompany/TravelCompany/Program.cs b/TravelCompany/TravelCompany/Program.cs index 9d57be6..40f6dc2 100644 --- a/TravelCompany/TravelCompany/Program.cs +++ b/TravelCompany/TravelCompany/Program.cs @@ -7,6 +7,8 @@ using TravelCompanyDatabaseImplement.Implements; using TravelCompanyBusinessLogic.BusinessLogic; using TravelCompanyBusinessLogic.OfficePackage.Implements; using TravelCompanyBusinessLogic.OfficePackage; +using TravelCompanyBusinessLogic.MailWorker; +using TravelCompanyContracts.BindingModels; namespace TravelCompany { @@ -26,6 +28,26 @@ namespace TravelCompany var services = new ServiceCollection(); ConfigureServices(services); _serviceProvider = services.BuildServiceProvider(); + try + { + var mailSender = _serviceProvider.GetService(); + mailSender?.MailConfig(new MailConfigBindingModel + { + MailLogin = System.Configuration.ConfigurationManager.AppSettings["MailLogin"] ?? string.Empty, + MailPassword = System.Configuration.ConfigurationManager.AppSettings["MailPassword"] ?? string.Empty, + SmtpClientHost = System.Configuration.ConfigurationManager.AppSettings["SmtpClientHost"] ?? string.Empty, + SmtpClientPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["SmtpClientPort"]), + PopHost = System.Configuration.ConfigurationManager.AppSettings["PopHost"] ?? string.Empty, + PopPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["PopPort"]) + }); + + var timer = new System.Threading.Timer(new TimerCallback(MailCheck!), null, 0, 100000); + } + catch (Exception ex) + { + var logger = _serviceProvider.GetService(); + logger?.LogError(ex, " "); + } Application.Run(_serviceProvider.GetRequiredService()); } private static void ConfigureServices(ServiceCollection services) @@ -40,6 +62,7 @@ namespace TravelCompany services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -47,6 +70,7 @@ namespace TravelCompany services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -59,12 +83,12 @@ namespace TravelCompany services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); - - + services.AddSingleton(); } - + private static void MailCheck(object obj) => ServiceProvider?.GetService()?.MailCheck(); } } diff --git a/TravelCompany/TravelCompany/TravelCompany.csproj b/TravelCompany/TravelCompany/TravelCompany.csproj index b290874..b4f9429 100644 --- a/TravelCompany/TravelCompany/TravelCompany.csproj +++ b/TravelCompany/TravelCompany/TravelCompany.csproj @@ -40,6 +40,9 @@ + + Always + Always diff --git a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/ClientLogic.cs b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/ClientLogic.cs index ffd23ee..32bef32 100644 --- a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/ClientLogic.cs +++ b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/ClientLogic.cs @@ -9,6 +9,7 @@ using TravelCompanyContracts.SearchModels; using TravelCompanyContracts.StoragesContracts; using TravelCompanyContracts.ViewModels; using Microsoft.Extensions.Logging; +using System.Text.RegularExpressions; namespace TravelCompanyBusinessLogic.BusinessLogic { @@ -16,6 +17,8 @@ namespace TravelCompanyBusinessLogic.BusinessLogic { private readonly ILogger _logger; private readonly IClientStorage _clientStorage; + private Regex validateEmailRegex = new Regex("^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"); + private Regex validatePasswordRegex = new Regex("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).(?=.*?[#?!@$%+^&*-]).{10,50}$"); public ClientLogic(ILogger logger, IClientStorage clientStorage) { @@ -111,6 +114,14 @@ namespace TravelCompanyBusinessLogic.BusinessLogic { throw new ArgumentNullException("У пользователя нет пароля!", nameof(model.Password)); } + if (!validateEmailRegex.IsMatch(model.Email)) + { + throw new InvalidOperationException("Почта введена некорректно!"); + } + if (!validatePasswordRegex.IsMatch(model.Password)) + { + throw new InvalidOperationException("Пароль не удовлетворяет требованиям"); + } _logger.LogInformation("Client. ClientFIO:{ClientFIO}. Password:{Password}." + " Email:{Email}. Id:{Id}", model.ClientFIO, model.Password, model.Email, model.Id); var element = _clientStorage.GetElement(new ClientSearchModel diff --git a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/MessageInfoLogic.cs b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/MessageInfoLogic.cs new file mode 100644 index 0000000..58e2f6c --- /dev/null +++ b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/MessageInfoLogic.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TravelCompanyContracts.BindingModels; +using TravelCompanyContracts.BusinessLogicsContracts; +using TravelCompanyContracts.SearchModels; +using TravelCompanyContracts.StoragesContracts; +using TravelCompanyContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace TravelCompanyBusinessLogic.BusinessLogic +{ + public class MessageInfoLogic : IMessageInfoLogic + { + private readonly ILogger _logger; + private readonly IMessageInfoStorage _messageStorage; + private readonly IClientLogic _clientLogic; + + public MessageInfoLogic(ILogger logger, IMessageInfoStorage logic, IClientLogic clientLogic) + { + _logger = logger; + _messageStorage = logic; + _clientLogic = clientLogic; + } + + public List? ReadList(MessageInfoSearchModel? model) + { + _logger.LogInformation("ReadList. MessageId:{MessageId}. ClientId:{ClientId}.", model?.MessageId, model?.ClientId); + var list = model == null ? _messageStorage.GetFullList() : _messageStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + + public bool Create(MessageInfoBindingModel model) + { + CheckModel(model); + model.ClientId = _clientLogic.ReadElement(new ClientSearchModel() { Email = model.SenderName })?.Id; + if (_messageStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + + private void CheckModel(MessageInfoBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.MessageId)) + { + throw new ArgumentNullException("Нет id письма!", nameof(model.MessageId)); + } + if (string.IsNullOrEmpty(model.SenderName)) + { + throw new ArgumentNullException("Нет отправителя!", nameof(model.SenderName)); + } + if (string.IsNullOrEmpty(model.Subject)) + { + throw new ArgumentNullException("Пустая тема письма!", nameof(model.Subject)); + } + if (string.IsNullOrEmpty(model.Body)) + { + throw new ArgumentNullException("Пустой текст письма!", nameof(model.Subject)); + } + _logger.LogInformation("MessageInfo. MessageId:{MessageId}. SenderName:{SenderName}. Subject:{Subject}. Body:{Body}", model.MessageId, model.SenderName, model.Subject, model.Body); + } + } +} diff --git a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs index 50dcb94..5c6e6e4 100644 --- a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs +++ b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using TravelCompanyBusinessLogic.MailWorker; using TravelCompanyContracts.BindingModels; using TravelCompanyContracts.BusinessLogicsContracts; using TravelCompanyContracts.SearchModels; @@ -17,22 +18,32 @@ namespace TravelCompanyBusinessLogic.BusinessLogic { private readonly ILogger _logger; private readonly IOrderStorage _orderStorage; + private readonly AbstractMailWorker _mailWorker; static readonly object _lock = new object(); - public OrderLogic(ILogger logger, IOrderStorage orderStorage) + public OrderLogic(ILogger logger, IOrderStorage orderStorage, AbstractMailWorker mailWorker) { _logger = logger; _orderStorage = orderStorage; + _mailWorker = mailWorker; } public bool CreateOrder(OrderBindingModel model) { CheckModel(model); if (model.Status != OrderStatus.Неизвестен) return false; model.Status = OrderStatus.Принят; - if (_orderStorage.Insert(model) == null) + var order = _orderStorage.Insert(model); + if (order == null) { _logger.LogWarning("Insert operation failed"); return false; } + _mailWorker.MailSendAsync(new MailSendInfoBindingModel() + { + MailAddress = order.ClientEmail, + Subject = "Создан заказ №" + order.Id, + Text = $"Создан заказ №{order.Id} от {order.DateCreate} на путешествие {order.TravelName} в количестве {order.Count} шт. Сумма заказа: {order.Sum}." + + }); return true; } @@ -55,7 +66,13 @@ namespace TravelCompanyBusinessLogic.BusinessLogic } model.Status = OrderStatus.Выдан; model.DateImplement = DateTime.Now; - _orderStorage.Update(model); + var order = _orderStorage.Update(model); + _mailWorker.MailSendAsync(new MailSendInfoBindingModel() + { + MailAddress = order.ClientEmail, + Subject = $"Заказ №{order.Id}. Статус изменен на Выдан", + Text = $"Выдан заказ №{order.Id} от {order.DateCreate} на путешествие {order.TravelName} в количестве {order.Count} шт. Сумма заказа: {order.Sum}." + }); return true; } @@ -78,7 +95,14 @@ namespace TravelCompanyBusinessLogic.BusinessLogic } model.Status = OrderStatus.Готов; model.DateImplement = DateTime.Now; - _orderStorage.Update(model); + var order = _orderStorage.Update(model); + _mailWorker.MailSendAsync(new MailSendInfoBindingModel() + { + MailAddress = order.ClientEmail, + Subject = $"Заказ №{order.Id}. Статус изменен на Готов", + Text = $"Готов заказ №{order.Id} от {order.DateCreate} на путешествие {order.TravelName} в количестве {order.Count} шт. Сумма заказа: {order.Sum}." + + }); return true; } @@ -133,7 +157,14 @@ namespace TravelCompanyBusinessLogic.BusinessLogic "в статус принятого перед его выполнением!"); } model.Status = OrderStatus.Выполняется; - _orderStorage.Update(model); + var order = _orderStorage.Update(model); + _mailWorker.MailSendAsync(new MailSendInfoBindingModel() + { + MailAddress = order.ClientEmail, + Subject = $"Заказ №{order.Id}. Статус изменен на Выполняется", + Text = $"Выполняется заказ №{order.Id} от {order.DateCreate} на путешествие {order.TravelName} в количестве {order.Count} шт. Сумма заказа: {order.Sum}." + + }); return true; } } diff --git a/TravelCompany/TravelCompanyBusinessLogic/MailWorker/AbstractMailWorker.cs b/TravelCompany/TravelCompanyBusinessLogic/MailWorker/AbstractMailWorker.cs new file mode 100644 index 0000000..b240d87 --- /dev/null +++ b/TravelCompany/TravelCompanyBusinessLogic/MailWorker/AbstractMailWorker.cs @@ -0,0 +1,85 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TravelCompanyContracts.BindingModels; +using TravelCompanyContracts.BusinessLogicsContracts; + +namespace TravelCompanyBusinessLogic.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; + public AbstractMailWorker(ILogger logger, + IMessageInfoLogic messageInfoLogic) + { + _logger = logger; + _messageInfoLogic = messageInfoLogic; + } + 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) + { + _messageInfoLogic.Create(mail); + } + } + protected abstract Task SendMailAsync(MailSendInfoBindingModel info); + protected abstract Task> + ReceiveMailAsync(); + } +} diff --git a/TravelCompany/TravelCompanyBusinessLogic/MailWorker/MailKitWorker.cs b/TravelCompany/TravelCompanyBusinessLogic/MailWorker/MailKitWorker.cs new file mode 100644 index 0000000..2d20541 --- /dev/null +++ b/TravelCompany/TravelCompanyBusinessLogic/MailWorker/MailKitWorker.cs @@ -0,0 +1,82 @@ +using MailKit.Net.Pop3; +using MailKit.Security; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Mail; +using System.Text; +using System.Threading.Tasks; +using TravelCompanyContracts.BindingModels; +using TravelCompanyContracts.BusinessLogicsContracts; + +namespace TravelCompanyBusinessLogic.MailWorker +{ + public class MailKitWorker : AbstractMailWorker + { + public MailKitWorker(ILogger logger, IMessageInfoLogic messageInfoLogic) : base(logger, messageInfoLogic) { } + 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/TravelCompany/TravelCompanyBusinessLogic/TravelCompanyBusinessLogic.csproj b/TravelCompany/TravelCompanyBusinessLogic/TravelCompanyBusinessLogic.csproj index 9ef71bf..2325811 100644 --- a/TravelCompany/TravelCompanyBusinessLogic/TravelCompanyBusinessLogic.csproj +++ b/TravelCompany/TravelCompanyBusinessLogic/TravelCompanyBusinessLogic.csproj @@ -8,6 +8,7 @@ + diff --git a/TravelCompany/TravelCompanyClientApp/Controllers/HomeController.cs b/TravelCompany/TravelCompanyClientApp/Controllers/HomeController.cs index ec6335d..2a5d967 100644 --- a/TravelCompany/TravelCompanyClientApp/Controllers/HomeController.cs +++ b/TravelCompany/TravelCompanyClientApp/Controllers/HomeController.cs @@ -147,5 +147,15 @@ string.IsNullOrEmpty(password)) ); return count * (prod?.Price ?? 1); } + + [HttpGet] + public IActionResult Mails() + { + if (APIClient.Client == null) + { + return Redirect("~/Home/Enter"); + } + return View(APIClient.GetRequest>($"api/client/getmessages?clientId={APIClient.Client.Id}")); + } } } diff --git a/TravelCompany/TravelCompanyClientApp/TravelCompanyClientApp.csproj b/TravelCompany/TravelCompanyClientApp/TravelCompanyClientApp.csproj index ce2298a..9b69867 100644 --- a/TravelCompany/TravelCompanyClientApp/TravelCompanyClientApp.csproj +++ b/TravelCompany/TravelCompanyClientApp/TravelCompanyClientApp.csproj @@ -14,4 +14,12 @@ + + + + + + <_ContentIncludedByDefault Remove="Views\Home\Mails.cshtml" /> + + diff --git a/TravelCompany/TravelCompanyClientApp/Views/Home/Mails.cshtml b/TravelCompany/TravelCompanyClientApp/Views/Home/Mails.cshtml new file mode 100644 index 0000000..1d2f80e --- /dev/null +++ b/TravelCompany/TravelCompanyClientApp/Views/Home/Mails.cshtml @@ -0,0 +1,54 @@ +@using TravelCompanyContracts.ViewModels + +@model List + +@{ + ViewData["Title"] = "Mails"; +} + +
+

Заказы

+
+ + +
+ @{ + if (Model == null) + { +

Авторизируйтесь

+ return; + } + + + + + + + + + + + @foreach (var item in Model) + { + + + + + + } + +
+ Дата письма + + Заголовок + + Текст +
+ @Html.DisplayFor(modelItem => item.DateDelivery) + + @Html.DisplayFor(modelItem => item.Subject) + + @Html.DisplayFor(modelItem => item.Body) +
+ } +
\ No newline at end of file diff --git a/TravelCompany/TravelCompanyClientApp/Views/Shared/_Layout.cshtml b/TravelCompany/TravelCompanyClientApp/Views/Shared/_Layout.cshtml index 075e74a..99c4094 100644 --- a/TravelCompany/TravelCompanyClientApp/Views/Shared/_Layout.cshtml +++ b/TravelCompany/TravelCompanyClientApp/Views/Shared/_Layout.cshtml @@ -24,6 +24,9 @@ Заказы +