From 160a66c8b883940ac382b3fc87c1ed540c41b3b8 Mon Sep 17 00:00:00 2001 From: bulatova_karina Date: Sat, 18 May 2024 13:19:48 +0400 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusinessLogics/ClientLogic.cs | 28 +++--- .../BusinessLogics/MessageInfoLogic.cs | 89 +++++++++++++++++++ .../BusinessLogics/OrderLogic.cs | 31 ++++--- .../ComputersShopBusinessLogic.csproj | 1 + .../MailWorker/AbstractMailWorker.cs | 84 +++++++++++++++++ .../MailWorker/MailKitWorker.cs | 76 ++++++++++++++++ .../Controllers/HomeController.cs | 62 +++++++------ .../Views/Home/Mails.cshtml | 54 +++++++++++ .../Views/Shared/_Layout.cshtml | 3 + .../BindingModels/MailConfigBindingModel.cs | 18 ++++ .../BindingModels/MailSendInfoBindingModel.cs | 15 ++++ .../BindingModels/MessageInfoBindingModel.cs | 19 ++++ .../IMessageInfoLogic.cs | 17 ++++ .../SearchModels/MessageInfoSearchModel.cs | 14 +++ .../StoragesContracts/IClientStorage.cs | 2 +- .../StoragesContracts/IMessageInfoStorage.cs | 19 ++++ .../ViewModels/MessageInfoViewModel.cs | 27 ++++++ .../ViewModels/OrderViewModel.cs | 4 + .../Models/IMessageInfoModel.cs | 18 ++++ .../ComputerShopDatabase.cs | 3 +- .../Implements/ClientStorage.cs | 38 ++++---- .../Implements/MessageInfoStorage.cs | 62 +++++++++++++ ... 20240518091255_InitialCreate.Designer.cs} | 43 ++++++++- ...ate.cs => 20240518091255_InitialCreate.cs} | 29 ++++++ .../ComputersShopDatabaseModelSnapshot.cs | 41 +++++++++ .../Models/Client.cs | 18 +++- .../Models/MessageInfo.cs | 63 +++++++++++++ .../Models/Order.cs | 2 + .../DataFileSingleton.cs | 23 +---- .../Implements/ClientStorage.cs | 27 +++--- .../Implements/MessageInfoStorage.cs | 63 +++++++++++++ .../Models/MessageInfo.cs | 80 +++++++++++++++++ .../DataListSingleton.cs | 3 + .../Implements/ClientStorage.cs | 9 +- .../Implements/MessageInfoStorage.cs | 74 +++++++++++++++ .../Implements/OrderStorage.cs | 2 +- .../Models/MessageInfo.cs | 46 ++++++++++ .../Controllers/ClientController.cs | 30 +++++-- ComputersShop/ComputersShopRestApi/Program.cs | 15 ++++ .../ComputersShopRestApi/appsettings.json | 8 +- ComputersShop/ComputersShopView/App.config | 11 +++ .../ComputersShopView/FormMails.Designer.cs | 63 +++++++++++++ ComputersShop/ComputersShopView/FormMails.cs | 50 +++++++++++ .../ComputersShopView/FormMails.resx | 60 +++++++++++++ .../ComputersShopView/FormMain.Designer.cs | 12 ++- ComputersShop/ComputersShopView/FormMain.cs | 8 ++ ComputersShop/ComputersShopView/Program.cs | 30 +++++++ 47 files changed, 1378 insertions(+), 116 deletions(-) create mode 100644 ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs create mode 100644 ComputersShop/ComputersShopBusinessLogic/MailWorker/AbstractMailWorker.cs create mode 100644 ComputersShop/ComputersShopBusinessLogic/MailWorker/MailKitWorker.cs create mode 100644 ComputersShop/ComputersShopClientApp/Views/Home/Mails.cshtml create mode 100644 ComputersShop/ComputersShopContracts/BindingModels/MailConfigBindingModel.cs create mode 100644 ComputersShop/ComputersShopContracts/BindingModels/MailSendInfoBindingModel.cs create mode 100644 ComputersShop/ComputersShopContracts/BindingModels/MessageInfoBindingModel.cs create mode 100644 ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IMessageInfoLogic.cs create mode 100644 ComputersShop/ComputersShopContracts/SearchModels/MessageInfoSearchModel.cs create mode 100644 ComputersShop/ComputersShopContracts/StoragesContracts/IMessageInfoStorage.cs create mode 100644 ComputersShop/ComputersShopContracts/ViewModels/MessageInfoViewModel.cs create mode 100644 ComputersShop/ComputersShopDataModels/Models/IMessageInfoModel.cs create mode 100644 ComputersShop/ComputersShopDatabaseImplement/Implements/MessageInfoStorage.cs rename ComputersShop/ComputersShopDatabaseImplement/Migrations/{20240505073421_InitialCreate.Designer.cs => 20240518091255_InitialCreate.Designer.cs} (85%) rename ComputersShop/ComputersShopDatabaseImplement/Migrations/{20240505073421_InitialCreate.cs => 20240518091255_InitialCreate.cs} (85%) create mode 100644 ComputersShop/ComputersShopDatabaseImplement/Models/MessageInfo.cs create mode 100644 ComputersShop/ComputersShopFileImplement/Implements/MessageInfoStorage.cs create mode 100644 ComputersShop/ComputersShopFileImplement/Models/MessageInfo.cs create mode 100644 ComputersShop/ComputersShopListImplement/Implements/MessageInfoStorage.cs create mode 100644 ComputersShop/ComputersShopListImplement/Models/MessageInfo.cs create mode 100644 ComputersShop/ComputersShopView/App.config create mode 100644 ComputersShop/ComputersShopView/FormMails.Designer.cs create mode 100644 ComputersShop/ComputersShopView/FormMails.cs create mode 100644 ComputersShop/ComputersShopView/FormMails.resx diff --git a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/ClientLogic.cs b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/ClientLogic.cs index 2bd0be1..93b1986 100644 --- a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/ClientLogic.cs +++ b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/ClientLogic.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using ComputersShopContracts.BindingModels; using ComputersShopContracts.BusinessLogicsContracts; @@ -23,14 +24,14 @@ namespace ComputersShopBusinessLogic.BusinessLogics } public List? ReadList(ClientSearchModel? model) { - _logger.LogInformation("ReadList. Email:{Email}. Id:{Id}", model?.Email, model?.Id); - var list = model == null ? _clientStorage.GetFullList() : _clientStorage.GetFiltredList(model); + _logger.LogInformation("ReadList. Email: {Email}. Id: {Id} ", model?.Email, model?.Id); + var list = (model == null) ? _clientStorage.GetFullList() : _clientStorage.GetFilteredList(model); if (list == null) { _logger.LogWarning("ReadList return null list"); return null; } - _logger.LogInformation("ReadList. Count:{Count}", list.Count); + _logger.LogInformation("ReadList. Count: {Count}", list.Count); return list; } public ClientViewModel? ReadElement(ClientSearchModel model) @@ -39,14 +40,14 @@ namespace ComputersShopBusinessLogic.BusinessLogics { throw new ArgumentNullException(nameof(model)); } - _logger.LogInformation("ReadElement. Email:{Email}. Id:{Id}", model.Email, model.Id); + _logger.LogInformation("ReadElement. Client email: {Email}. Client id: {Id}", model.Email, model.Id); var element = _clientStorage.GetElement(model); if (element == null) { _logger.LogWarning("ReadElement element not found"); return null; } - _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + _logger.LogInformation("ReadElement find. Id: {Id}", element.Id); return element; } public bool Create(ClientBindingModel model) @@ -72,7 +73,7 @@ namespace ComputersShopBusinessLogic.BusinessLogics public bool Delete(ClientBindingModel model) { CheckModel(model, false); - _logger.LogInformation("Delete. Id:{Id}", model.Id); + _logger.LogInformation("Delete. Id: {Id}", model.Id); if (_clientStorage.Delete(model) == null) { _logger.LogWarning("Delete operation failed"); @@ -94,20 +95,23 @@ namespace ComputersShopBusinessLogic.BusinessLogics { throw new ArgumentNullException("Нет ФИО клиента", nameof(model.ClientFIO)); } - if (string.IsNullOrEmpty(model.Email)) + if (string.IsNullOrEmpty(model.Email) || !Regex.IsMatch(model.Email, @"^[a-z0-9._%+-]+\@([a-z0-9-]+\.)+[a-z]{2,4}$")) { - throw new ArgumentNullException("Нет эл. почты", nameof(model.Email)); + throw new ArgumentNullException("Некорректно введен логин(почта) клиента", nameof(model.Email)); } - - _logger.LogInformation("Client. Id:{Id}. FIO:{ClientFIO}. Email:{Email}.", model.Id, model.ClientFIO, model.Email); - + if (string.IsNullOrEmpty(model.Password) || !Regex.IsMatch(model.Password, @"^(?=.*[A-Za-z])(?=.*\d)(?=.*[^A-Za-z0-9\n]).{10,50}$")) + { + throw new ArgumentNullException("Некорректно введен пароль клиента", nameof(model.Password)); + } + _logger.LogInformation("Client. Id: {id}, FIO: {fio}, email: {email}, password: {password}", model.Id, model.ClientFIO, model.Email, + model.Password); var element = _clientStorage.GetElement(new ClientSearchModel { Email = model.Email }); if (element != null && element.Id != model.Id) { - throw new InvalidOperationException("Клиент с такой эл. пойтой уже есть"); + throw new InvalidOperationException("Клиент с таким логином(почтой) уже есть"); } } } diff --git a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs new file mode 100644 index 0000000..6d139c1 --- /dev/null +++ b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs @@ -0,0 +1,89 @@ +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.StoragesContracts; +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.BusinessLogicsContracts; +using ComputersShopContracts.ViewModels; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopBusinessLogic.BusinessLogics +{ + public class MessageInfoLogic : IMessageInfoLogic + { + private readonly ILogger _logger; + private readonly IMessageInfoStorage _messageInfoStorage; + private readonly IClientStorage _clientStorage; + public MessageInfoLogic(ILogger logger, IMessageInfoStorage messageInfoStorage, IClientStorage clientStorage) + { + _logger = logger; + _messageInfoStorage = messageInfoStorage; + _clientStorage = clientStorage; + } + public List? ReadList(MessageInfoSearchModel? model) + { + _logger.LogInformation("ReadList. MessageId: {MessageId}. ClientId: {ClientId}", model?.MessageId, model?.ClientId); + var list = model == null ? _messageInfoStorage.GetFullList() : _messageInfoStorage.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); + if (_messageInfoStorage.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}. DateDelivery: {DateDelivery} Subject: {Subject}. Body: {Body}", model.MessageId, model.SenderName, model.DateDelivery, model.Subject, model.Body); + var element = _clientStorage.GetElement(new ClientSearchModel + { + Email = model.SenderName + }); + if (element == null) + { + _logger.LogWarning("Не удалось найти клиента, отправившего письмо с адреса Email: {Email}", model.SenderName); + } + else + { + model.ClientId = element.Id; + } + } + } +} diff --git a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/OrderLogic.cs b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/OrderLogic.cs index 5442ed9..568118f 100644 --- a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/OrderLogic.cs +++ b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/OrderLogic.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using ComputersShopBusinessLogic.MailWorker; using ComputersShopContracts.BindingModels; using ComputersShopContracts.BusinessLogicsContracts; using ComputersShopContracts.SearchModels; @@ -19,14 +20,15 @@ namespace ComputersShopBusinessLogic.BusinessLogics private readonly IOrderStorage _orderStorage; - static readonly object locker = new(); + private readonly AbstractMailWorker _mailWorker; - public OrderLogic(ILogger logger, IOrderStorage orderStorage) + static readonly object locker = new(); + public OrderLogic(ILogger logger, IOrderStorage orderStorage, AbstractMailWorker mailWorker) { _logger = logger; _orderStorage = orderStorage; + _mailWorker = mailWorker; } - public bool CreateOrder(OrderBindingModel model) { CheckModel(model); @@ -36,14 +38,20 @@ namespace ComputersShopBusinessLogic.BusinessLogics return false; } model.Status = OrderStatus.Принят; - if (_orderStorage.Insert(model) == null) + var element = _orderStorage.Insert(model); + if (element == null) { _logger.LogWarning("Insert operation failed"); return false; } + Task.Run(() => _mailWorker.MailSendAsync(new MailSendInfoBindingModel + { + MailAddress = element.ClientEmail, + Subject = $"Новый заказ создан. Номер заказа - {element.Id}", + Text = $"Заказ №{element.Id} от {element.DateCreate} на сумму {element.Sum} принят." + })); return true; } - public List? ReadList(OrderSearchModel? model) { _logger.LogInformation("ReadList. OrderId: {Id}.", model?.Id); @@ -56,7 +64,6 @@ namespace ComputersShopBusinessLogic.BusinessLogics _logger.LogInformation("ReadList. Count: {Count}", list.Count); return list; } - public OrderViewModel? ReadElement(OrderSearchModel model) { if (model == null) @@ -73,7 +80,6 @@ namespace ComputersShopBusinessLogic.BusinessLogics _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); return element; } - public bool TakeOrderInWork(OrderBindingModel model) { lock (locker) @@ -81,17 +87,14 @@ namespace ComputersShopBusinessLogic.BusinessLogics return ChangeStatus(model, OrderStatus.Выполняется); } } - public bool FinishOrder(OrderBindingModel model) { return ChangeStatus(model, OrderStatus.Готов); } - public bool DeliveryOrder(OrderBindingModel model) { return ChangeStatus(model, OrderStatus.Выдан); } - private void CheckModel(OrderBindingModel model, bool withParams = true) { if (model == null) @@ -121,7 +124,6 @@ namespace ComputersShopBusinessLogic.BusinessLogics _logger.LogInformation("Order. Id: {Id}. Sum: {Sum}. ComputerId: {ComputerId}. ComputerCount: {Count}", model.Id, model.Sum, model.ComputerId, model.Count); } - private bool ChangeStatus(OrderBindingModel model, OrderStatus newStatus) { CheckModel(model, false); @@ -155,6 +157,13 @@ namespace ComputersShopBusinessLogic.BusinessLogics _logger.LogWarning("Change status operation failed"); return false; } + string DateInfo = model.DateImplement.HasValue ? $"Дата выполнения {model.DateImplement}" : ""; + Task.Run(() => _mailWorker.MailSendAsync(new MailSendInfoBindingModel + { + MailAddress = order.ClientEmail, + Subject = $"Заказ №{order.Id}", + Text = $"Заказ №{order.Id} изменен статус на {model.Status}. {DateInfo}" + })); return true; } } diff --git a/ComputersShop/ComputersShopBusinessLogic/ComputersShopBusinessLogic.csproj b/ComputersShop/ComputersShopBusinessLogic/ComputersShopBusinessLogic.csproj index 1fee6c8..3e3e673 100644 --- a/ComputersShop/ComputersShopBusinessLogic/ComputersShopBusinessLogic.csproj +++ b/ComputersShop/ComputersShopBusinessLogic/ComputersShopBusinessLogic.csproj @@ -9,6 +9,7 @@ + diff --git a/ComputersShop/ComputersShopBusinessLogic/MailWorker/AbstractMailWorker.cs b/ComputersShop/ComputersShopBusinessLogic/MailWorker/AbstractMailWorker.cs new file mode 100644 index 0000000..36fcf6d --- /dev/null +++ b/ComputersShop/ComputersShopBusinessLogic/MailWorker/AbstractMailWorker.cs @@ -0,0 +1,84 @@ +using ComputersShopBusinessLogic.BusinessLogics; +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.BusinessLogicsContracts; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopBusinessLogic.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/ComputersShop/ComputersShopBusinessLogic/MailWorker/MailKitWorker.cs b/ComputersShop/ComputersShopBusinessLogic/MailWorker/MailKitWorker.cs new file mode 100644 index 0000000..ac433f8 --- /dev/null +++ b/ComputersShop/ComputersShopBusinessLogic/MailWorker/MailKitWorker.cs @@ -0,0 +1,76 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.BusinessLogicsContracts; +using MailKit.Net.Pop3; +using MailKit.Security; +using Microsoft.Extensions.Logging; +using System.Net; +using System.Net.Mail; +using System.Text; + +namespace ComputersShopBusinessLogic.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/ComputersShop/ComputersShopClientApp/Controllers/HomeController.cs b/ComputersShop/ComputersShopClientApp/Controllers/HomeController.cs index d14a2be..39846e6 100644 --- a/ComputersShop/ComputersShopClientApp/Controllers/HomeController.cs +++ b/ComputersShop/ComputersShopClientApp/Controllers/HomeController.cs @@ -11,19 +11,21 @@ namespace ComputersShopClientApp.Controllers public class HomeController : Controller { private readonly ILogger _logger; + public HomeController(ILogger logger) { _logger = logger; } + public IActionResult Index() { if (APIClient.Client == null) { return Redirect("~/Home/Enter"); } - return - View(APIClient.GetRequest>($"api/main/getorders?clientId={APIClient.Client.Id}")); + return View(APIClient.GetRequest>($"api/main/getorders?clientId={APIClient.Client.Id}")); } + [HttpGet] public IActionResult Privacy() { @@ -33,6 +35,7 @@ namespace ComputersShopClientApp.Controllers } return View(APIClient.Client); } + [HttpPost] public void Privacy(string login, string password, string fio) { @@ -40,8 +43,7 @@ namespace ComputersShopClientApp.Controllers { throw new Exception("Вы как суда попали? Суда вход только авторизованным"); } - if (string.IsNullOrEmpty(login) || - string.IsNullOrEmpty(password) || string.IsNullOrEmpty(fio)) + if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(fio)) { throw new Exception("Введите логин, пароль и ФИО"); } @@ -52,57 +54,54 @@ namespace ComputersShopClientApp.Controllers Email = login, Password = password }); + APIClient.Client.ClientFIO = fio; APIClient.Client.Email = login; APIClient.Client.Password = password; Response.Redirect("Index"); } - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, - NoStore = true)] + + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { - return View(new ErrorViewModel - { - RequestId = - Activity.Current?.Id ?? HttpContext.TraceIdentifier - }); + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } + [HttpGet] public IActionResult Enter() { return View(); } + [HttpPost] public void Enter(string login, string password) { - if (string.IsNullOrEmpty(login) || - string.IsNullOrEmpty(password)) + if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password)) { throw new Exception("Введите логин и пароль"); } - APIClient.Client = - APIClient.GetRequest($"api/client/login?login={login}&password={password}"); + APIClient.Client = APIClient.GetRequest($"api/client/login?login={login}&password={password}"); if (APIClient.Client == null) { throw new Exception("Неверный логин/пароль"); } Response.Redirect("Index"); } + [HttpGet] public IActionResult Register() { return View(); } + [HttpPost] public void Register(string login, string password, string fio) { - if (string.IsNullOrEmpty(login) || - string.IsNullOrEmpty(password) || string.IsNullOrEmpty(fio)) + if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(fio)) { throw new Exception("Введите логин, пароль и ФИО"); } - APIClient.PostRequest("api/client/register", new - ClientBindingModel + APIClient.PostRequest("api/client/register", new ClientBindingModel { ClientFIO = fio, Email = login, @@ -111,13 +110,14 @@ namespace ComputersShopClientApp.Controllers Response.Redirect("Enter"); return; } + [HttpGet] public IActionResult Create() { - ViewBag.Computers = - APIClient.GetRequest>("api/main/getcomputerlist"); + ViewBag.Computers = APIClient.GetRequest>("api/main/getcomputerlist"); return View(); } + [HttpPost] public void Create(int computer, int count) { @@ -129,8 +129,7 @@ namespace ComputersShopClientApp.Controllers { throw new Exception("Количество и сумма должны быть больше 0"); } - APIClient.PostRequest("api/main/createorder", new - OrderBindingModel + APIClient.PostRequest("api/main/createorder", new OrderBindingModel { ClientId = APIClient.Client.Id, ComputerId = computer, @@ -139,13 +138,22 @@ namespace ComputersShopClientApp.Controllers }); Response.Redirect("Index"); } + [HttpPost] public double Calc(int count, int computer) { - var prod = - APIClient.GetRequest($"api/main/getcomputer?computerId={computer}" - ); - return count * (prod?.Price ?? 1); + var ic = APIClient.GetRequest($"api/main/getcomputer?computerId={computer}"); + return count * (ic?.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}")); } } } \ No newline at end of file diff --git a/ComputersShop/ComputersShopClientApp/Views/Home/Mails.cshtml b/ComputersShop/ComputersShopClientApp/Views/Home/Mails.cshtml new file mode 100644 index 0000000..1e7afc2 --- /dev/null +++ b/ComputersShop/ComputersShopClientApp/Views/Home/Mails.cshtml @@ -0,0 +1,54 @@ +@using ComputersShopContracts.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/ComputersShop/ComputersShopClientApp/Views/Shared/_Layout.cshtml b/ComputersShop/ComputersShopClientApp/Views/Shared/_Layout.cshtml index 0a13e61..b5d0ec5 100644 --- a/ComputersShop/ComputersShopClientApp/Views/Shared/_Layout.cshtml +++ b/ComputersShop/ComputersShopClientApp/Views/Shared/_Layout.cshtml @@ -27,6 +27,9 @@ + diff --git a/ComputersShop/ComputersShopContracts/BindingModels/MailConfigBindingModel.cs b/ComputersShop/ComputersShopContracts/BindingModels/MailConfigBindingModel.cs new file mode 100644 index 0000000..c26ddf2 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/BindingModels/MailConfigBindingModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.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/ComputersShop/ComputersShopContracts/BindingModels/MailSendInfoBindingModel.cs b/ComputersShop/ComputersShopContracts/BindingModels/MailSendInfoBindingModel.cs new file mode 100644 index 0000000..6d1e5dc --- /dev/null +++ b/ComputersShop/ComputersShopContracts/BindingModels/MailSendInfoBindingModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.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/ComputersShop/ComputersShopContracts/BindingModels/MessageInfoBindingModel.cs b/ComputersShop/ComputersShopContracts/BindingModels/MessageInfoBindingModel.cs new file mode 100644 index 0000000..37eb64c --- /dev/null +++ b/ComputersShop/ComputersShopContracts/BindingModels/MessageInfoBindingModel.cs @@ -0,0 +1,19 @@ +using ComputersShopDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.BindingModels +{ + public class MessageInfoBindingModel : IMessageInfoModel + { + public string MessageId { get; set; } = string.Empty; + public int? ClientId { get; set; } + public string SenderName { get; set; } = string.Empty; + public string Subject { get; set; } = string.Empty; + public string Body { get; set; } = string.Empty; + public DateTime DateDelivery { get; set; } + } +} diff --git a/ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IMessageInfoLogic.cs b/ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IMessageInfoLogic.cs new file mode 100644 index 0000000..1a01187 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IMessageInfoLogic.cs @@ -0,0 +1,17 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.BusinessLogicsContracts +{ + public interface IMessageInfoLogic + { + List? ReadList(MessageInfoSearchModel? model); + bool Create(MessageInfoBindingModel model); + } +} diff --git a/ComputersShop/ComputersShopContracts/SearchModels/MessageInfoSearchModel.cs b/ComputersShop/ComputersShopContracts/SearchModels/MessageInfoSearchModel.cs new file mode 100644 index 0000000..84c16ed --- /dev/null +++ b/ComputersShop/ComputersShopContracts/SearchModels/MessageInfoSearchModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.SearchModels +{ + public class MessageInfoSearchModel + { + public int? ClientId { get; set; } + public string? MessageId { get; set; } + } +} diff --git a/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs b/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs index e9903aa..abd2b99 100644 --- a/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs +++ b/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs @@ -12,7 +12,7 @@ namespace ComputersShopContracts.StoragesContracts public interface IClientStorage { List GetFullList(); - List GetFiltredList(ClientSearchModel model); + List GetFilteredList(ClientSearchModel model); ClientViewModel? GetElement(ClientSearchModel model); ClientViewModel? Insert(ClientBindingModel model); ClientViewModel? Update(ClientBindingModel model); diff --git a/ComputersShop/ComputersShopContracts/StoragesContracts/IMessageInfoStorage.cs b/ComputersShop/ComputersShopContracts/StoragesContracts/IMessageInfoStorage.cs new file mode 100644 index 0000000..e06914a --- /dev/null +++ b/ComputersShop/ComputersShopContracts/StoragesContracts/IMessageInfoStorage.cs @@ -0,0 +1,19 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.StoragesContracts +{ + public interface IMessageInfoStorage + { + List GetFullList(); + List GetFilteredList(MessageInfoSearchModel model); + MessageInfoViewModel? GetElement(MessageInfoSearchModel model); + MessageInfoViewModel? Insert(MessageInfoBindingModel model); + } +} diff --git a/ComputersShop/ComputersShopContracts/ViewModels/MessageInfoViewModel.cs b/ComputersShop/ComputersShopContracts/ViewModels/MessageInfoViewModel.cs new file mode 100644 index 0000000..cf1de86 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/ViewModels/MessageInfoViewModel.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopContracts.ViewModels +{ + public class MessageInfoViewModel + { + public string MessageId { get; set; } = string.Empty; + public int? ClientId { get; set; } + + [DisplayName("Отправитель")] + public string SenderName { get; set; } = string.Empty; + + [DisplayName("Дата письма")] + public DateTime DateDelivery { get; set; } + + [DisplayName("Заголовок")] + public string Subject { get; set; } = string.Empty; + + [DisplayName("Текст")] + public string Body { get; set; } = string.Empty; + } +} diff --git a/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs b/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs index 7039e3a..b823472 100644 --- a/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs +++ b/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs @@ -18,10 +18,14 @@ namespace ComputersShopContracts.ViewModels [DisplayName("Компьютер")] public string ComputerName { get; set; } = string.Empty; + public int ClientId { get; set; } [DisplayName("ФИО клиента")] public string ClientFIO { get; set; } = string.Empty; + + public string ClientEmail { get; set; } = string.Empty; + public int? ImplementerId { get; set; } [DisplayName("ФИО исполнителя")] diff --git a/ComputersShop/ComputersShopDataModels/Models/IMessageInfoModel.cs b/ComputersShop/ComputersShopDataModels/Models/IMessageInfoModel.cs new file mode 100644 index 0000000..aa325ce --- /dev/null +++ b/ComputersShop/ComputersShopDataModels/Models/IMessageInfoModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopDataModels.Models +{ + public interface IMessageInfoModel + { + string MessageId { get; } + int? ClientId { get; } + string SenderName { get; } + DateTime DateDelivery { get; } + string Subject { get; } + string Body { get; } + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/ComputerShopDatabase.cs b/ComputersShop/ComputersShopDatabaseImplement/ComputerShopDatabase.cs index 7c59ee5..7d7d0dc 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/ComputerShopDatabase.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/ComputerShopDatabase.cs @@ -15,7 +15,7 @@ namespace ComputersShopDatabaseImplement { if (optionsBuilder.IsConfigured == false) { - optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-1DE5E8N\SQLEXPRESS;Initial Catalog=ComputersShopDatabaseFull2; + optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-1DE5E8N\SQLEXPRESS;Initial Catalog=ComputersShopDatabaseNew; Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True"); } base.OnConfiguring(optionsBuilder); @@ -26,5 +26,6 @@ namespace ComputersShopDatabaseImplement public virtual DbSet Orders { set; get; } public virtual DbSet Clients { set; get; } public virtual DbSet Implementers { set; get; } + public virtual DbSet MessageInfos { set; get; } } } diff --git a/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs b/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs index 6e79b07..22c7c95 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs @@ -16,55 +16,62 @@ namespace ComputersShopDatabaseImplement.Implements public List GetFullList() { using var context = new ComputersShopDatabase(); - return context.Clients.Select(x => x.GetViewModel).ToList(); + return context.Clients + .Select(x => x.GetViewModel) + .ToList(); } - public List GetFiltredList(ClientSearchModel model) + public List GetFilteredList(ClientSearchModel model) { if (string.IsNullOrEmpty(model.Email)) { return new(); } using var context = new ComputersShopDatabase(); - return context.Clients.Where(x => x.Email.Contains(model.Email)).Select(x => x.GetViewModel).ToList(); + return context.Clients + .Where(x => x.Email.Contains(model.Email)) + .Select(x => x.GetViewModel) + .ToList(); } public ClientViewModel? GetElement(ClientSearchModel model) { - if (string.IsNullOrEmpty(model.Email) && !model.Id.HasValue) + if (string.IsNullOrEmpty(model.Email) && string.IsNullOrEmpty(model.Password) && !model.Id.HasValue) { return null; } using var context = new ComputersShopDatabase(); - return context.Clients.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Email) - && x.Email == model.Email) || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; + return context.Clients.FirstOrDefault(x => + (!string.IsNullOrEmpty(model.Email) && x.Email == model.Email && !string.IsNullOrEmpty(model.Password) && x.Password == model.Password) + || (!string.IsNullOrEmpty(model.Email) && x.Email == model.Email && string.IsNullOrEmpty(model.Password)) + || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; } public ClientViewModel? Insert(ClientBindingModel model) { - var newComponent = Client.Create(model); - if (newComponent == null) + var newClient = Client.Create(model); + if (newClient == null) { return null; } using var context = new ComputersShopDatabase(); - context.Clients.Add(newComponent); + context.Clients.Add(newClient); context.SaveChanges(); - return newComponent.GetViewModel; + return newClient.GetViewModel; } public ClientViewModel? Update(ClientBindingModel model) { using var context = new ComputersShopDatabase(); - var component = context.Clients.FirstOrDefault(x => x.Id == model.Id); - if (component == null) + var client = context.Clients.FirstOrDefault(x => x.Id == model.Id); + if (client == null) { return null; } - component.Update(model); + client.Update(model); context.SaveChanges(); - return component.GetViewModel; + return client.GetViewModel; } public ClientViewModel? Delete(ClientBindingModel model) { using var context = new ComputersShopDatabase(); - var element = context.Clients.FirstOrDefault(rec => rec.Id == model.Id); + var element = context.Clients.FirstOrDefault(x => x.Id == model.Id); if (element != null) { context.Clients.Remove(element); @@ -75,3 +82,4 @@ namespace ComputersShopDatabaseImplement.Implements } } } + diff --git a/ComputersShop/ComputersShopDatabaseImplement/Implements/MessageInfoStorage.cs b/ComputersShop/ComputersShopDatabaseImplement/Implements/MessageInfoStorage.cs new file mode 100644 index 0000000..9e6a4ff --- /dev/null +++ b/ComputersShop/ComputersShopDatabaseImplement/Implements/MessageInfoStorage.cs @@ -0,0 +1,62 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.StoragesContracts; +using ComputersShopContracts.ViewModels; +using ComputersShopDatabaseImplement.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopDatabaseImplement.Implements +{ + public class MessageInfoStorage : IMessageInfoStorage + { + public List GetFullList() + { + using var context = new ComputersShopDatabase(); + return context.MessageInfos + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFilteredList(MessageInfoSearchModel model) + { + if (!model.ClientId.HasValue) + { + return new(); + } + using var context = new ComputersShopDatabase(); + return context.MessageInfos + .Where(x => x.ClientId.HasValue && x.ClientId == model.ClientId) + .Select(x => x.GetViewModel) + .ToList(); + } + + public MessageInfoViewModel? GetElement(MessageInfoSearchModel model) + { + if (string.IsNullOrEmpty(model.MessageId)) + { + return new(); + } + using var context = new ComputersShopDatabase(); + return context.MessageInfos + .FirstOrDefault(x => model.MessageId.Equals(x.MessageId)) + ?.GetViewModel; + } + + public MessageInfoViewModel? Insert(MessageInfoBindingModel model) + { + var newMessage = MessageInfo.Create(model); + if (newMessage == null) + { + return null; + } + using var context = new ComputersShopDatabase(); + context.MessageInfos.Add(newMessage); + context.SaveChanges(); + return newMessage.GetViewModel; + } + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240505073421_InitialCreate.Designer.cs b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240518091255_InitialCreate.Designer.cs similarity index 85% rename from ComputersShop/ComputersShopDatabaseImplement/Migrations/20240505073421_InitialCreate.Designer.cs rename to ComputersShop/ComputersShopDatabaseImplement/Migrations/20240518091255_InitialCreate.Designer.cs index fe87e4b..a999074 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240505073421_InitialCreate.Designer.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240518091255_InitialCreate.Designer.cs @@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace ComputersShopDatabaseImplement.Migrations { [DbContext(typeof(ComputersShopDatabase))] - [Migration("20240505073421_InitialCreate")] + [Migration("20240518091255_InitialCreate")] partial class InitialCreate { /// @@ -143,6 +143,36 @@ namespace ComputersShopDatabaseImplement.Migrations b.ToTable("Implementers"); }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.MessageInfo", b => + { + b.Property("MessageId") + .HasColumnType("nvarchar(450)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("DateDelivery") + .HasColumnType("datetime2"); + + b.Property("SenderName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.ToTable("MessageInfos"); + }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => { b.Property("Id") @@ -205,6 +235,15 @@ namespace ComputersShopDatabaseImplement.Migrations b.Navigation("Computer"); }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.MessageInfo", b => + { + b.HasOne("ComputersShopDatabaseImplement.Models.Client", "Client") + .WithMany("ClientMessages") + .HasForeignKey("ClientId"); + + b.Navigation("Client"); + }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => { b.HasOne("ComputersShopDatabaseImplement.Models.Client", "Client") @@ -232,6 +271,8 @@ namespace ComputersShopDatabaseImplement.Migrations modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Client", b => { + b.Navigation("ClientMessages"); + b.Navigation("Orders"); }); diff --git a/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240505073421_InitialCreate.cs b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240518091255_InitialCreate.cs similarity index 85% rename from ComputersShop/ComputersShopDatabaseImplement/Migrations/20240505073421_InitialCreate.cs rename to ComputersShop/ComputersShopDatabaseImplement/Migrations/20240518091255_InitialCreate.cs index 87cfccc..566099c 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240505073421_InitialCreate.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20240518091255_InitialCreate.cs @@ -70,6 +70,27 @@ namespace ComputersShopDatabaseImplement.Migrations table.PrimaryKey("PK_Implementers", x => x.Id); }); + migrationBuilder.CreateTable( + name: "MessageInfos", + columns: table => new + { + MessageId = table.Column(type: "nvarchar(450)", nullable: false), + ClientId = table.Column(type: "int", nullable: true), + SenderName = table.Column(type: "nvarchar(max)", nullable: false), + DateDelivery = table.Column(type: "datetime2", nullable: false), + Subject = table.Column(type: "nvarchar(max)", nullable: false), + Body = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MessageInfos", x => x.MessageId); + table.ForeignKey( + name: "FK_MessageInfos_Clients_ClientId", + column: x => x.ClientId, + principalTable: "Clients", + principalColumn: "Id"); + }); + migrationBuilder.CreateTable( name: "ComputerComponents", columns: table => new @@ -144,6 +165,11 @@ namespace ComputersShopDatabaseImplement.Migrations table: "ComputerComponents", column: "ComputerId"); + migrationBuilder.CreateIndex( + name: "IX_MessageInfos_ClientId", + table: "MessageInfos", + column: "ClientId"); + migrationBuilder.CreateIndex( name: "IX_Orders_ClientId", table: "Orders", @@ -166,6 +192,9 @@ namespace ComputersShopDatabaseImplement.Migrations migrationBuilder.DropTable( name: "ComputerComponents"); + migrationBuilder.DropTable( + name: "MessageInfos"); + migrationBuilder.DropTable( name: "Orders"); diff --git a/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs b/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs index f4e6de2..91f649c 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs @@ -140,6 +140,36 @@ namespace ComputersShopDatabaseImplement.Migrations b.ToTable("Implementers"); }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.MessageInfo", b => + { + b.Property("MessageId") + .HasColumnType("nvarchar(450)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("DateDelivery") + .HasColumnType("datetime2"); + + b.Property("SenderName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.ToTable("MessageInfos"); + }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => { b.Property("Id") @@ -202,6 +232,15 @@ namespace ComputersShopDatabaseImplement.Migrations b.Navigation("Computer"); }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.MessageInfo", b => + { + b.HasOne("ComputersShopDatabaseImplement.Models.Client", "Client") + .WithMany("ClientMessages") + .HasForeignKey("ClientId"); + + b.Navigation("Client"); + }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => { b.HasOne("ComputersShopDatabaseImplement.Models.Client", "Client") @@ -229,6 +268,8 @@ namespace ComputersShopDatabaseImplement.Migrations modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Client", b => { + b.Navigation("ClientMessages"); + b.Navigation("Orders"); }); diff --git a/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs b/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs index 19b5635..c50ff57 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs @@ -14,28 +14,37 @@ namespace ComputersShopDatabaseImplement.Models public class Client : IClientModel { public int Id { get; private set; } + [Required] public string ClientFIO { get; private set; } = string.Empty; + [Required] public string Email { get; private set; } = string.Empty; + [Required] public string Password { get; private set; } = string.Empty; + [ForeignKey("ClientId")] public virtual List Orders { get; set; } = new(); + + [ForeignKey("ClientId")] + public virtual List ClientMessages { get; set; } = new(); + public static Client? Create(ClientBindingModel model) { if (model == null) { return null; } - return new Client() + return new() { Id = model.Id, ClientFIO = model.ClientFIO, Email = model.Email, - Password = model.Password, + Password = model.Password }; } + public void Update(ClientBindingModel model) { if (model == null) @@ -46,12 +55,13 @@ namespace ComputersShopDatabaseImplement.Models Email = model.Email; Password = model.Password; } + public ClientViewModel GetViewModel => new() { Id = Id, ClientFIO = ClientFIO, Email = Email, - Password = Password, + Password = Password }; } -} +} \ No newline at end of file diff --git a/ComputersShop/ComputersShopDatabaseImplement/Models/MessageInfo.cs b/ComputersShop/ComputersShopDatabaseImplement/Models/MessageInfo.cs new file mode 100644 index 0000000..1349d0b --- /dev/null +++ b/ComputersShop/ComputersShopDatabaseImplement/Models/MessageInfo.cs @@ -0,0 +1,63 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.ViewModels; +using ComputersShopDataModels.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopDatabaseImplement.Models +{ + public class MessageInfo : IMessageInfoModel + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public string MessageId { get; set; } = string.Empty; + + public int? ClientId { get; set; } + + [Required] + public string SenderName { get; set; } = string.Empty; + + [Required] + public DateTime DateDelivery { get; set; } + + [Required] + public string Subject { get; set; } = string.Empty; + + [Required] + public string Body { get; set; } = string.Empty; + + public virtual Client? Client { get; set; } + + public static MessageInfo? Create(MessageInfoBindingModel? model) + { + if (model == null) + { + return null; + } + return new() + { + MessageId = model.MessageId, + ClientId = model.ClientId, + SenderName = model.SenderName, + DateDelivery = model.DateDelivery, + Subject = model.Subject, + Body = model.Body + }; + } + + public MessageInfoViewModel GetViewModel => new() + { + MessageId = MessageId, + ClientId = ClientId, + SenderName = SenderName, + DateDelivery = DateDelivery, + Subject = Subject, + Body = Body + }; + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs b/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs index 772c1ca..efa255f 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs @@ -86,7 +86,9 @@ namespace ComputersShopDatabaseImplement.Models DateImplement = DateImplement, ComputerName = Computer.ComputerName ?? string.Empty, ClientFIO = Client.ClientFIO ?? string.Empty, + ClientEmail = Client.Email ?? string.Empty, ImplementerFIO = Implementer?.ImplementerFIO ?? string.Empty }; } } + diff --git a/ComputersShop/ComputersShopFileImplement/DataFileSingleton.cs b/ComputersShop/ComputersShopFileImplement/DataFileSingleton.cs index 4adfa6c..4b7a4d7 100644 --- a/ComputersShop/ComputersShopFileImplement/DataFileSingleton.cs +++ b/ComputersShop/ComputersShopFileImplement/DataFileSingleton.cs @@ -12,27 +12,18 @@ namespace ComputersShopFileImplement internal class DataFileSingleton { private static DataFileSingleton? instance; - private readonly string ComponentFileName = "Component.xml"; - private readonly string OrderFileName = "Order.xml"; - private readonly string ComputerFileName = "Computer.xml"; - private readonly string ClientFileName = "Client.xml"; - private readonly string ImplementerFileName = "Implementer.xml"; - + private readonly string MessageInfoFileName = "MessageInfo.xml"; public List Components { get; private set; } - public List Orders { get; private set; } - public List Computers { get; private set; } - public List Clients { get; private set; } - public List Implementers { get; private set; } - + public List Messages { get; private set; } public static DataFileSingleton GetInstance() { if (instance == null) @@ -41,17 +32,12 @@ namespace ComputersShopFileImplement } return instance; } - public void SaveComponents() => SaveData(Components, ComponentFileName, "Components", x => x.GetXElement); - public void SaveComputers() => SaveData(Computers, ComputerFileName, "Computers", x => x.GetXElement); - public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement); - public void SaveClients() => SaveData(Clients, ClientFileName, "Clients", x => x.GetXElement); - public void SaveImplementers() => SaveData(Implementers, ImplementerFileName, "Implementers", x => x.GetXElement); - + public void SaveMessages() => SaveData(Orders, ImplementerFileName, "Messages", x => x.GetXElement); private DataFileSingleton() { Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!; @@ -59,8 +45,8 @@ namespace ComputersShopFileImplement Orders = LoadData(OrderFileName, "Order", x => Order.Create(x)!)!; Clients = LoadData(ClientFileName, "Client", x => Client.Create(x)!)!; Implementers = LoadData(ImplementerFileName, "Implementer", x => Implementer.Create(x)!)!; + Messages = LoadData(MessageInfoFileName, "MessageInfo", x => MessageInfo.Create(x)!)!; } - private static List? LoadData(string filename, string xmlNodeName, Func selectFunction) { if (File.Exists(filename)) @@ -69,7 +55,6 @@ namespace ComputersShopFileImplement } return new List(); } - private static void SaveData(List data, string filename, string xmlNodeName, Func selectFunction) { if (data != null) diff --git a/ComputersShop/ComputersShopFileImplement/Implements/ClientStorage.cs b/ComputersShop/ComputersShopFileImplement/Implements/ClientStorage.cs index 88d0005..1917a44 100644 --- a/ComputersShop/ComputersShopFileImplement/Implements/ClientStorage.cs +++ b/ComputersShop/ComputersShopFileImplement/Implements/ClientStorage.cs @@ -20,28 +20,32 @@ namespace ComputersShopFileImplement.Implements } public List GetFullList() { - return source.Clients.Select(x => x.GetViewModel).ToList(); + return source.Clients + .Select(x => x.GetViewModel) + .ToList(); } - public List GetFiltredList(ClientSearchModel model) + public List GetFilteredList(ClientSearchModel model) { if (string.IsNullOrEmpty(model.Email)) { return new(); } return source.Clients - .Where(x => x.Email.Contains(model.Email)) - .Select(x => x.GetViewModel).ToList(); + .Where(x => x.Email.Contains(model.Email)) + .Select(x => x.GetViewModel) + .ToList(); } public ClientViewModel? GetElement(ClientSearchModel model) { - if (!string.IsNullOrEmpty(model.Email) && !model.Id.HasValue) + if (string.IsNullOrEmpty(model.Email) && string.IsNullOrEmpty(model.Password) && !model.Id.HasValue) { return null; } return source.Clients - .FirstOrDefault(x => (!string.IsNullOrEmpty(model.Email) && - x.Email == model.Email) || (model.Id.HasValue && - x.Id == model.Id))?.GetViewModel; + .FirstOrDefault(x => + (!string.IsNullOrEmpty(model.Email) && x.Email == model.Email && !string.IsNullOrEmpty(model.Password) && x.Password == model.Password) + || (!string.IsNullOrEmpty(model.Email) && x.Email == model.Email && string.IsNullOrEmpty(model.Password)) + || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; } public ClientViewModel? Insert(ClientBindingModel model) { @@ -52,7 +56,7 @@ namespace ComputersShopFileImplement.Implements return null; } source.Clients.Add(newClient); - source.SaveComponents(); + source.SaveClients(); return newClient.GetViewModel; } public ClientViewModel? Update(ClientBindingModel model) @@ -63,7 +67,7 @@ namespace ComputersShopFileImplement.Implements return null; } client.Update(model); - source.SaveComponents(); + source.SaveClients(); return client.GetViewModel; } public ClientViewModel? Delete(ClientBindingModel model) @@ -72,10 +76,11 @@ namespace ComputersShopFileImplement.Implements if (element != null) { source.Clients.Remove(element); - source.SaveComponents(); + source.SaveClients(); return element.GetViewModel; } return null; } } } + diff --git a/ComputersShop/ComputersShopFileImplement/Implements/MessageInfoStorage.cs b/ComputersShop/ComputersShopFileImplement/Implements/MessageInfoStorage.cs new file mode 100644 index 0000000..34e2521 --- /dev/null +++ b/ComputersShop/ComputersShopFileImplement/Implements/MessageInfoStorage.cs @@ -0,0 +1,63 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.StoragesContracts; +using ComputersShopContracts.ViewModels; +using ComputersShopFileImplement.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopFileImplement.Implements +{ + public class MessageInfoStorage : IMessageInfoStorage + { + private readonly DataFileSingleton _source; + + public MessageInfoStorage() + { + _source = DataFileSingleton.GetInstance(); + } + + public List GetFullList() + { + return _source.Messages + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFilteredList(MessageInfoSearchModel model) + { + if (!model.ClientId.HasValue) + { + return new(); + } + return _source.Messages + .Where(x => x.ClientId.HasValue && x.ClientId == model.ClientId) + .Select(x => x.GetViewModel) + .ToList(); + } + + public MessageInfoViewModel? GetElement(MessageInfoSearchModel model) + { + if (string.IsNullOrEmpty(model.MessageId)) + { + return null; + } + return _source.Messages.FirstOrDefault(x => model.MessageId.Equals(x.MessageId))?.GetViewModel; + } + + public MessageInfoViewModel? Insert(MessageInfoBindingModel model) + { + var newMessage = MessageInfo.Create(model); + if (newMessage == null) + { + return null; + } + _source.Messages.Add(newMessage); + _source.SaveMessages(); + return newMessage.GetViewModel; + } + } +} diff --git a/ComputersShop/ComputersShopFileImplement/Models/MessageInfo.cs b/ComputersShop/ComputersShopFileImplement/Models/MessageInfo.cs new file mode 100644 index 0000000..8bd1a73 --- /dev/null +++ b/ComputersShop/ComputersShopFileImplement/Models/MessageInfo.cs @@ -0,0 +1,80 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.ViewModels; +using ComputersShopDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace ComputersShopFileImplement.Models +{ + public class MessageInfo : IMessageInfoModel + { + public string MessageId { get; private set; } = string.Empty; + + public int? ClientId { get; private set; } + + public string SenderName { get; private set; } = string.Empty; + + public DateTime DateDelivery { get; private set; } = DateTime.Now; + + public string Subject { get; private set; } = string.Empty; + + public string Body { get; private set; } = string.Empty; + + public static MessageInfo? Create(MessageInfoBindingModel model) + { + if (model == null) + { + return null; + } + return new() + { + MessageId = model.MessageId, + ClientId = model.ClientId, + SenderName = model.SenderName, + DateDelivery = model.DateDelivery, + Subject = model.Subject, + Body = model.Body + }; + } + + public static MessageInfo? Create(XElement element) + { + if (element == null) + { + return null; + } + return new() + { + MessageId = element.Attribute("MessageId")!.Value, + ClientId = Convert.ToInt32(element.Element("ClientId")!.Value), + SenderName = element.Element("SenderName")!.Value, + DateDelivery = Convert.ToDateTime(element.Element("DateDelivery")!.Value), + Subject = element.Element("Subject")!.Value, + Body = element.Element("Body")!.Value + }; + } + + public MessageInfoViewModel GetViewModel => new() + { + MessageId = MessageId, + ClientId = ClientId, + SenderName = SenderName, + DateDelivery = DateDelivery, + Subject = Subject, + Body = Body + }; + + public XElement GetXElement => new("MessageInfo", + new XAttribute("MessageId", MessageId), + new XElement("ClientId", ClientId), + new XElement("SenderName", SenderName), + new XElement("DateDelivery", DateDelivery), + new XElement("Subject", Subject), + new XElement("Body", Body) + ); + } +} diff --git a/ComputersShop/ComputersShopListImplement/DataListSingleton.cs b/ComputersShop/ComputersShopListImplement/DataListSingleton.cs index 0e283a4..666c2d4 100644 --- a/ComputersShop/ComputersShopListImplement/DataListSingleton.cs +++ b/ComputersShop/ComputersShopListImplement/DataListSingleton.cs @@ -21,6 +21,8 @@ namespace AbstractShopListImplement public List Implementers { get; set; } + public List Messages { get; set; } + private DataListSingleton() { Components = new List(); @@ -28,6 +30,7 @@ namespace AbstractShopListImplement Computers = new List(); Clients = new List(); Implementers = new List(); + Messages = new List(); } public static DataListSingleton GetInstance() diff --git a/ComputersShop/ComputersShopListImplement/Implements/ClientStorage.cs b/ComputersShop/ComputersShopListImplement/Implements/ClientStorage.cs index e576130..d703c14 100644 --- a/ComputersShop/ComputersShopListImplement/Implements/ClientStorage.cs +++ b/ComputersShop/ComputersShopListImplement/Implements/ClientStorage.cs @@ -28,7 +28,7 @@ namespace ComputersShopListImplement.Implements } return result; } - public List GetFiltredList(ClientSearchModel model) + public List GetFilteredList(ClientSearchModel model) { var result = new List(); if (string.IsNullOrEmpty(model.Email)) @@ -46,14 +46,14 @@ namespace ComputersShopListImplement.Implements } public ClientViewModel? GetElement(ClientSearchModel model) { - if (string.IsNullOrEmpty(model.Email) && !model.Id.HasValue) + if (string.IsNullOrEmpty(model.Email) && string.IsNullOrEmpty(model.Password) && !model.Id.HasValue) { return null; } foreach (var client in _source.Clients) { - if ((!string.IsNullOrEmpty(model.Email) - && client.Email == model.Email) + if ((!string.IsNullOrEmpty(model.Email) && client.Email == model.Email && !string.IsNullOrEmpty(model.Password) && client.Password == model.Password) + || (!string.IsNullOrEmpty(model.Email) && client.Email == model.Email && string.IsNullOrEmpty(model.Password)) || (model.Id.HasValue && client.Id == model.Id)) { return client.GetViewModel; @@ -106,3 +106,4 @@ namespace ComputersShopListImplement.Implements } } } + diff --git a/ComputersShop/ComputersShopListImplement/Implements/MessageInfoStorage.cs b/ComputersShop/ComputersShopListImplement/Implements/MessageInfoStorage.cs new file mode 100644 index 0000000..f1e1850 --- /dev/null +++ b/ComputersShop/ComputersShopListImplement/Implements/MessageInfoStorage.cs @@ -0,0 +1,74 @@ +using AbstractShopListImplement; +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.StoragesContracts; +using ComputersShopContracts.ViewModels; +using ComputersShopListImplement.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopListImplement.Implements +{ + public class MessageInfoStorage : IMessageInfoStorage + { + private readonly DataListSingleton _source; + public MessageInfoStorage() + { + _source = DataListSingleton.GetInstance(); + } + + public List GetFullList() + { + var result = new List(); + foreach (var message in _source.Messages) + { + result.Add(message.GetViewModel); + } + return result; + } + public List GetFilteredList(MessageInfoSearchModel model) + { + var result = new List(); + if (!model.ClientId.HasValue) + { + return result; + } + foreach (var message in _source.Messages) + { + if (message.ClientId.HasValue && message.ClientId == model.ClientId) + { + result.Add(message.GetViewModel); + } + } + return result; + } + public MessageInfoViewModel? GetElement(MessageInfoSearchModel model) + { + if (string.IsNullOrEmpty(model.MessageId)) + { + return null; + } + foreach (var message in _source.Messages) + { + if (model.MessageId.Equals(message.MessageId)) + { + return message.GetViewModel; + } + } + return null; + } + public MessageInfoViewModel? Insert(MessageInfoBindingModel model) + { + var newMessage = MessageInfo.Create(model); + if (newMessage == null) + { + return null; + } + _source.Messages.Add(newMessage); + return newMessage.GetViewModel; + } + } +} diff --git a/ComputersShop/ComputersShopListImplement/Implements/OrderStorage.cs b/ComputersShop/ComputersShopListImplement/Implements/OrderStorage.cs index e068a51..2a3d89a 100644 --- a/ComputersShop/ComputersShopListImplement/Implements/OrderStorage.cs +++ b/ComputersShop/ComputersShopListImplement/Implements/OrderStorage.cs @@ -151,7 +151,7 @@ namespace ComputersShopListImplement.Implements } private OrderViewModel AddInfo(OrderViewModel model) { - var selectedComputer = _source.Computers.Find(iceCream => iceCream.Id == model.ComputerId); + var selectedComputer = _source.Computers.Find(computer => computer.Id == model.ComputerId); if (selectedComputer != null) { model.ComputerName = selectedComputer.ComputerName; diff --git a/ComputersShop/ComputersShopListImplement/Models/MessageInfo.cs b/ComputersShop/ComputersShopListImplement/Models/MessageInfo.cs new file mode 100644 index 0000000..b5e97e7 --- /dev/null +++ b/ComputersShop/ComputersShopListImplement/Models/MessageInfo.cs @@ -0,0 +1,46 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.ViewModels; +using ComputersShopDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComputersShopListImplement.Models +{ + public class MessageInfo : IMessageInfoModel + { + public string MessageId { get; private set; } = string.Empty; + public int? ClientId { get; private set; } + public string SenderName { get; private set; } = string.Empty; + public DateTime DateDelivery { get; private set; } = DateTime.Now; + public string Subject { get; private set; } = string.Empty; + public string Body { get; private set; } = string.Empty; + public static MessageInfo? Create(MessageInfoBindingModel model) + { + if (model == null) + { + return null; + } + return new() + { + MessageId = model.MessageId, + ClientId = model.ClientId, + SenderName = model.SenderName, + DateDelivery = model.DateDelivery, + Subject = model.Subject, + Body = model.Body + }; + } + public MessageInfoViewModel GetViewModel => new() + { + MessageId = MessageId, + ClientId = ClientId, + SenderName = SenderName, + DateDelivery = DateDelivery, + Subject = Subject, + Body = Body + }; + } +} \ No newline at end of file diff --git a/ComputersShop/ComputersShopRestApi/Controllers/ClientController.cs b/ComputersShop/ComputersShopRestApi/Controllers/ClientController.cs index d407088..25d5292 100644 --- a/ComputersShop/ComputersShopRestApi/Controllers/ClientController.cs +++ b/ComputersShop/ComputersShopRestApi/Controllers/ClientController.cs @@ -13,13 +13,13 @@ namespace ComputersShopRestApi.Controllers { private readonly ILogger _logger; private readonly IClientLogic _logic; - - public ClientController(IClientLogic logic, ILogger logger) + private readonly IMessageInfoLogic _mailLogic; + public ClientController(IClientLogic logic, IMessageInfoLogic mailLogic, ILogger logger) { _logger = logger; _logic = logic; + _mailLogic = mailLogic; } - [HttpGet] public ClientViewModel? Login(string login, string password) { @@ -33,7 +33,7 @@ namespace ComputersShopRestApi.Controllers } catch (Exception ex) { - _logger.LogError(ex, "Ошибка входа в систему"); + _logger.LogError(ex, "Login error"); throw; } } @@ -46,7 +46,7 @@ namespace ComputersShopRestApi.Controllers } catch (Exception ex) { - _logger.LogError(ex, "Ошибка регистрации"); + _logger.LogError(ex, "Registration error"); throw; } } @@ -59,9 +59,25 @@ namespace ComputersShopRestApi.Controllers } catch (Exception ex) { - _logger.LogError(ex, "Ошибка обновления данных"); + _logger.LogError(ex, "Update data error"); + throw; + } + } + [HttpGet] + public List? GetMessages(int clientId) + { + try + { + return _mailLogic.ReadList(new MessageInfoSearchModel + { + ClientId = clientId + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error receiving client's emails"); throw; } } } -} \ No newline at end of file +} diff --git a/ComputersShop/ComputersShopRestApi/Program.cs b/ComputersShop/ComputersShopRestApi/Program.cs index c2556ff..c4b5ab6 100644 --- a/ComputersShop/ComputersShopRestApi/Program.cs +++ b/ComputersShop/ComputersShopRestApi/Program.cs @@ -1,4 +1,6 @@ using ComputersShopBusinessLogic.BusinessLogics; +using ComputersShopBusinessLogic.MailWorker; +using ComputersShopContracts.BindingModels; using ComputersShopContracts.BusinessLogicsContracts; using ComputersShopContracts.StoragesContracts; using ComputersShopDatabaseImplement.Implements; @@ -13,11 +15,13 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle @@ -29,6 +33,17 @@ builder.Services.AddSwaggerGen(c => var app = builder.Build(); +var mailSender = app.Services.GetService(); +mailSender?.MailConfig(new MailConfigBindingModel +{ + MailLogin = builder.Configuration?.GetSection("MailLogin")?.Value?.ToString() ?? string.Empty, + MailPassword = builder.Configuration?.GetSection("MailPassword")?.Value?.ToString() ?? string.Empty, + SmtpClientHost = builder.Configuration?.GetSection("SmtpClientHost")?.Value?.ToString() ?? string.Empty, + SmtpClientPort = Convert.ToInt32(builder.Configuration?.GetSection("SmtpClientPort")?.Value?.ToString()), + PopHost = builder.Configuration?.GetSection("PopHost")?.Value?.ToString() ?? string.Empty, + PopPort = Convert.ToInt32(builder.Configuration?.GetSection("PopPort")?.Value?.ToString()) +}); + // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { diff --git a/ComputersShop/ComputersShopRestApi/appsettings.json b/ComputersShop/ComputersShopRestApi/appsettings.json index 10f68b8..21f5e64 100644 --- a/ComputersShop/ComputersShopRestApi/appsettings.json +++ b/ComputersShop/ComputersShopRestApi/appsettings.json @@ -5,5 +5,11 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "SmtpClientHost": "smtp.gmail.com", + "SmtpClientPort": "587", + "PopHost": "pop.gmail.com", + "PopPort": "995", + "MailLogin": "midnight737475@gmail.com", + "MailPassword": "mzvm eqbk syuh vorl" } diff --git a/ComputersShop/ComputersShopView/App.config b/ComputersShop/ComputersShopView/App.config new file mode 100644 index 0000000..08eb797 --- /dev/null +++ b/ComputersShop/ComputersShopView/App.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ComputersShop/ComputersShopView/FormMails.Designer.cs b/ComputersShop/ComputersShopView/FormMails.Designer.cs new file mode 100644 index 0000000..aa7f97a --- /dev/null +++ b/ComputersShop/ComputersShopView/FormMails.Designer.cs @@ -0,0 +1,63 @@ +namespace ComputersShopView +{ + partial class FormMails + { + /// + /// 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.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView.Location = new System.Drawing.Point(0, 0); + this.dataGridView.Name = "dataGridView"; + this.dataGridView.RowHeadersWidth = 51; + this.dataGridView.RowTemplate.Height = 29; + this.dataGridView.Size = new System.Drawing.Size(641, 268); + this.dataGridView.TabIndex = 0; + // + // FormMails + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(641, 269); + this.Controls.Add(this.dataGridView); + this.Name = "FormMails"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Письма"; + ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private DataGridView dataGridView; + } +} \ No newline at end of file diff --git a/ComputersShop/ComputersShopView/FormMails.cs b/ComputersShop/ComputersShopView/FormMails.cs new file mode 100644 index 0000000..e546ce7 --- /dev/null +++ b/ComputersShop/ComputersShopView/FormMails.cs @@ -0,0 +1,50 @@ +using ComputersShopContracts.BusinessLogicsContracts; +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; + +namespace ComputersShopView +{ + public partial class FormMails : Form + { + private readonly ILogger _logger; + private readonly IMessageInfoLogic _logic; + public FormMails(ILogger logger, IMessageInfoLogic logic) + { + InitializeComponent(); + _logger = logger; + _logic = logic; + } + private void FormMails_Load(object sender, EventArgs e) + { + LoadData(); + } + private void LoadData() + { + 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("Messages loading"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Messages loading error"); + MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} diff --git a/ComputersShop/ComputersShopView/FormMails.resx b/ComputersShop/ComputersShopView/FormMails.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/ComputersShop/ComputersShopView/FormMails.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/ComputersShop/ComputersShopView/FormMain.Designer.cs b/ComputersShop/ComputersShopView/FormMain.Designer.cs index 22957f7..2001a0a 100644 --- a/ComputersShop/ComputersShopView/FormMain.Designer.cs +++ b/ComputersShop/ComputersShopView/FormMain.Designer.cs @@ -43,6 +43,7 @@ this.buttonCreateOrder = 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.menuStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit(); this.SuspendLayout(); @@ -53,7 +54,8 @@ this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.справочникиToolStripMenuItem, this.отчетыToolStripMenuItem, - this.запускРаботToolStripMenuItem}); + this.запускРаботToolStripMenuItem, + this.почтаToolStripMenuItem}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.Size = new System.Drawing.Size(1147, 28); @@ -181,6 +183,13 @@ this.buttonRef.UseVisualStyleBackColor = true; this.buttonRef.Click += new System.EventHandler(this.ButtonRef_Click); // + // почтаToolStripMenuItem + // + 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 // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); @@ -220,5 +229,6 @@ private ToolStripMenuItem клиентыToolStripMenuItem; private ToolStripMenuItem запускРаботToolStripMenuItem; private ToolStripMenuItem исполнителиToolStripMenuItem; + private ToolStripMenuItem почтаToolStripMenuItem; } } \ No newline at end of file diff --git a/ComputersShop/ComputersShopView/FormMain.cs b/ComputersShop/ComputersShopView/FormMain.cs index 32c59e7..1cc0894 100644 --- a/ComputersShop/ComputersShopView/FormMain.cs +++ b/ComputersShop/ComputersShopView/FormMain.cs @@ -169,6 +169,14 @@ namespace ComputersShopView form.ShowDialog(); } } + private void ПочтаToolStripMenuItem_Click(object sender, EventArgs e) + { + var service = Program.ServiceProvider?.GetService(typeof(FormMails)); + if (service is FormMails form) + { + form.ShowDialog(); + } + } } } diff --git a/ComputersShop/ComputersShopView/Program.cs b/ComputersShop/ComputersShopView/Program.cs index 72ab2d3..2c90e09 100644 --- a/ComputersShop/ComputersShopView/Program.cs +++ b/ComputersShop/ComputersShopView/Program.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; using System; +using ComputersShopBusinessLogic.MailWorker; +using ComputersShopContracts.BindingModels; namespace ComputersShopView { @@ -27,6 +29,26 @@ namespace ComputersShopView 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, "Mails Problem"); + } Application.Run(_serviceProvider.GetRequiredService()); } private static void ConfigureServices(ServiceCollection services) @@ -41,6 +63,7 @@ namespace ComputersShopView services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -48,7 +71,10 @@ namespace ComputersShopView services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddSingleton(); services.AddTransient(); services.AddTransient(); @@ -66,6 +92,10 @@ namespace ComputersShopView services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + } + + private static void MailCheck(object obj) => ServiceProvider?.GetService()?.MailCheck(); } } \ No newline at end of file