PIbd-21_MasenkinMS_LabWork07_Hard #14

Closed
Factorino73 wants to merge 6 commits from LabWork07_Hard into LabWork06_Hard
48 changed files with 3695 additions and 247 deletions

View File

@ -1,23 +0,0 @@
2024-04-08 10:12:55,009 INFO Microsoft.Hosting.Lifetime.? [?] - MESSAGE: Now listening on: https://localhost:7122
2024-04-08 10:12:55,090 INFO Microsoft.Hosting.Lifetime.? [?] - MESSAGE: Now listening on: http://localhost:5092
2024-04-08 10:12:55,097 INFO Microsoft.Hosting.Lifetime.OnApplicationStarted [0] - MESSAGE: Application started. Press Ctrl+C to shut down.
2024-04-08 10:12:55,100 INFO Microsoft.Hosting.Lifetime.OnApplicationStarted [0] - MESSAGE: Hosting environment: Development
2024-04-08 10:12:55,102 INFO Microsoft.Hosting.Lifetime.OnApplicationStarted [0] - MESSAGE: Content root path: D:\ULSTU\Семестр 4\РПП\AircraftPlant\AircraftPlantRestApi\
2024-04-08 10:13:00,428 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadList [49] - MESSAGE: ReadList. PlaneName:(null).Id:(null)
2024-04-08 10:13:03,695 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadList [58] - MESSAGE: ReadList. Count:2
2024-04-08 10:13:37,635 INFO AircraftPlantBusinessLogic.BusinessLogics.ClientLogic.ReadElement [74] - MESSAGE: ReadElement. ClientEmail:client1.Id:(null)
2024-04-08 10:13:37,766 INFO AircraftPlantBusinessLogic.BusinessLogics.ClientLogic.ReadElement [83] - MESSAGE: ReadElement find. Id:1
2024-04-08 10:13:37,802 INFO AircraftPlantBusinessLogic.BusinessLogics.ClientLogic.ReadElement [74] - MESSAGE: ReadElement. ClientEmail:client1.Id:(null)
2024-04-08 10:13:37,849 INFO AircraftPlantBusinessLogic.BusinessLogics.ClientLogic.ReadElement [83] - MESSAGE: ReadElement find. Id:1
2024-04-08 10:13:37,914 INFO AircraftPlantBusinessLogic.BusinessLogics.OrderLogic.ReadList [50] - MESSAGE: ReadList. Order.Id:(null)
2024-04-08 10:13:37,956 INFO AircraftPlantBusinessLogic.BusinessLogics.OrderLogic.ReadList [59] - MESSAGE: ReadList. Count:2
2024-04-08 10:13:45,625 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadList [49] - MESSAGE: ReadList. PlaneName:(null).Id:(null)
2024-04-08 10:13:45,628 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadList [58] - MESSAGE: ReadList. Count:2
2024-04-08 10:13:48,493 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadElement [75] - MESSAGE: ReadElement. PlaneName:(null).Id:1
2024-04-08 10:13:48,514 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadElement [84] - MESSAGE: ReadElement find. Id:1
2024-04-08 10:13:50,536 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadElement [75] - MESSAGE: ReadElement. PlaneName:(null).Id:1
2024-04-08 10:13:50,540 INFO AircraftPlantBusinessLogic.BusinessLogics.PlaneLogic.ReadElement [84] - MESSAGE: ReadElement find. Id:1
2024-04-08 10:13:50,584 INFO AircraftPlantBusinessLogic.BusinessLogics.OrderLogic.CheckModel [144] - MESSAGE: Order. OrderID:0.Sum:1650. PlaneId: 1
2024-04-08 10:13:50,780 INFO AircraftPlantBusinessLogic.BusinessLogics.OrderLogic.ReadList [50] - MESSAGE: ReadList. Order.Id:(null)
2024-04-08 10:13:50,783 INFO AircraftPlantBusinessLogic.BusinessLogics.OrderLogic.ReadList [59] - MESSAGE: ReadList. Count:3

View File

@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageReference Include="MailKit" Version="4.5.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
</ItemGroup>

View File

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace AircraftPlantBusinessLogic.BusinessLogics
@ -155,13 +156,13 @@ namespace AircraftPlantBusinessLogic.BusinessLogics
{
throw new ArgumentNullException("Нет ФИО клиента", nameof(model.ClientFIO));
}
if (string.IsNullOrEmpty(model.Email))
if (string.IsNullOrEmpty(model.Email) || !Regex.IsMatch(model.Email, @"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$", RegexOptions.IgnoreCase))
{
throw new ArgumentNullException("Нет почты клиента", nameof(model.Email));
throw new ArgumentNullException("Невалидная электронная почта клиента", nameof(model.Email));
}
if (string.IsNullOrEmpty(model.Password))
if (string.IsNullOrEmpty(model.Password) || !Regex.IsMatch(model.Password, @"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"))
{
throw new ArgumentNullException("Нет пароля клиента", nameof(model.Password));
throw new ArgumentNullException("Слабый пароль", nameof(model.Password));
}
_logger.LogInformation("Client. ClientFIO: {ClientFIO}. Email: {Email}. Id: {Id}", model.ClientFIO, model.Email, model.Id);

View File

@ -0,0 +1,127 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.StoragesContracts;
using AircraftPlantContracts.ViewModels;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantBusinessLogic.BusinessLogics
{
/// <summary>
/// Реализация интерфейса бизнес-логики для писем
/// </summary>
public class MessageInfoLogic : IMessageInfoLogic
{
/// <summary>
/// Логгер
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Взаимодействие с хранилищем писем
/// </summary>
private readonly IMessageInfoStorage _messageStorage;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
/// <param name="messageStorage"></param>
public MessageInfoLogic(ILogger<MessageInfoLogic> logger, IMessageInfoStorage messageStorage)
{
_logger = logger;
_messageStorage = messageStorage;
}
/// <summary>
/// Получение списка
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public List<MessageInfoViewModel>? 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;
}
/// <summary>
/// Получение отдельной записи
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public MessageInfoViewModel? ReadElement(MessageInfoSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
_logger.LogInformation("ReadElement. MessageId:{Id}", model.MessageId);
var element = _messageStorage.GetElement(model);
if (element == null)
{
_logger.LogWarning("ReadElement element not found");
return null;
}
_logger.LogInformation("ReadElement find. MessageId:{Id}", element.MessageId);
return element;
}
/// <summary>
/// Создание записи
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public bool Create(MessageInfoBindingModel model)
{
if (model == null)
{
return false;
}
if (_messageStorage.Insert(model) == null)
{
_logger.LogWarning("Insert operation failed");
return false;
}
return true;
}
/// <summary>
/// Изменение записи
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public bool Update(MessageInfoBindingModel model)
{
if (model == null)
{
return false;
}
if (_messageStorage.Update(model) == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
return true;
}
}
}

View File

@ -1,4 +1,5 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantBusinessLogic.MailWorker;
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.StoragesContracts;
@ -44,18 +45,35 @@ namespace AircraftPlantBusinessLogic.BusinessLogics
/// </summary>
private IPlaneStorage _planeStorage;
/// <summary>
/// Взаимодействие с хранилищем клиентов
/// </summary>
private readonly IClientStorage _clientStorage;
/// <summary>
/// Бизнес-логика для отправки писем
/// </summary>
private readonly AbstractMailWorker _mailLogic;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
/// <param name="orderStorage"></param>
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IShopStorage shopStorage, IShopLogic shopLogic, IPlaneStorage planeStorage)
/// <param name="shopStorage"></param>
/// <param name="shopLogic"></param>
/// <param name="planeStorage"></param>
/// <param name="clientStorage"></param>
/// <param name="mailLogic"></param>
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IShopStorage shopStorage, IShopLogic shopLogic, IPlaneStorage planeStorage, IClientStorage clientStorage, AbstractMailWorker mailLogic)
{
_logger = logger;
_orderStorage = orderStorage;
_shopStorage = shopStorage;
_shopLogic = shopLogic;
_planeStorage = planeStorage;
_clientStorage = clientStorage;
_mailLogic = mailLogic;
}
/// <summary>
@ -119,11 +137,14 @@ namespace AircraftPlantBusinessLogic.BusinessLogics
model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null)
var order = _orderStorage.Insert(model);
if (order == null)
{
_logger.LogWarning("Insert operation failed");
return false;
}
SendEmail(order);
return true;
}
@ -236,11 +257,14 @@ namespace AircraftPlantBusinessLogic.BusinessLogics
}
CheckModel(model, false);
if (_orderStorage.Update(model) == null)
var order = _orderStorage.Update(model);
if (order == null)
{
_logger.LogWarning("Change status operation failed");
return false;
}
SendEmail(order);
return true;
}
@ -317,5 +341,45 @@ namespace AircraftPlantBusinessLogic.BusinessLogics
}
return false;
}
/// <summary>
/// Отправить письмо
/// </summary>
/// <param name="model"></param>
public void SendEmail(OrderViewModel order)
{
if (order == null)
{
return;
}
var client = _clientStorage.GetElement(new ClientSearchModel { Id = order.ClientId });
if (client == null)
{
return;
}
MailSendInfoBindingModel mailModel;
if (order.Status == OrderStatus.Принят)
{
mailModel = new MailSendInfoBindingModel
{
MailAddress = client.Email,
Subject = $"Order №{order.Id}",
Text = $"Your order №{order.Id} by {order.DateCreate} on {order.Sum} was accepted!"
};
}
else
{
mailModel = new MailSendInfoBindingModel
{
MailAddress = client.Email,
Subject = $"Order №{order.Id}",
Text = $"Order №{order.Id} status was changed to {order.Status}"
};
}
_mailLogic.MailSendAsync(mailModel);
}
}
}

View File

@ -0,0 +1,160 @@
using AircraftPlantBusinessLogic.BusinessLogics;
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.SearchModels;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantBusinessLogic.MailWorker
{
/// <summary>
/// Абстрактный класс для работы с письмами
/// </summary>
public abstract class AbstractMailWorker
{
private readonly ILogger _logger;
/// <summary>
/// Логин для доступа к почтовому сервису
/// </summary>
protected string _mailLogin = string.Empty;
/// <summary>
/// Пароль для доступа к почтовому сервису
/// </summary>
protected string _mailPassword = string.Empty;
/// <summary>
/// Хост SMTP-клиента
/// </summary>
protected string _smtpClientHost = string.Empty;
/// <summary>
/// Порт SMTP-клиента
/// </summary>
protected int _smtpClientPort;
/// <summary>
/// Хост протокола POP3
/// </summary>
protected string _popHost = string.Empty;
/// <summary>
/// Порт протокола POP3
/// </summary>
protected int _popPort;
/// <summary>
/// Бизнес-логика для писем
/// </summary>
private readonly IMessageInfoLogic _messageInfoLogic;
/// <summary>
/// Бизнес-логика для клиентов
/// </summary>
private readonly IClientLogic _clientLogic;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
/// <param name="messageInfoLogic"></param>
public AbstractMailWorker(ILogger<AbstractMailWorker> logger, IMessageInfoLogic messageInfoLogic, IClientLogic clientLogic)
{
_logger = logger;
_messageInfoLogic = messageInfoLogic;
_clientLogic = clientLogic;
}
/// <summary>
/// Настроить почтовый сервис
/// </summary>
/// <param name="config"></param>
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);
}
/// <summary>
/// Проверить и отправить письмо
/// </summary>
/// <param name="info"></param>
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);
}
/// <summary>
/// Проверить новые письма
/// </summary>
public async void MailCheck()
{
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{
return;
}
if (string.IsNullOrEmpty(_popHost) || _popPort == 0)
{
return;
}
if (_messageInfoLogic == null)
{
return;
}
var list = await ReceiveMailAsync();
_logger.LogDebug("Check Mail: {Count} new mails", list.Count);
foreach (var mail in list)
{
mail.ClientId = _clientLogic.ReadElement(new ClientSearchModel
{
Email = mail.SenderName
})?.Id;
_messageInfoLogic.Create(mail);
}
}
/// <summary>
/// Отправить письмо
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
/// <summary>
/// Получить все письма
/// </summary>
/// <returns></returns>
protected abstract Task<List<MessageInfoBindingModel>> ReceiveMailAsync();
}
}

View File

@ -0,0 +1,103 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using MailKit.Net.Pop3;
using MailKit.Security;
namespace AircraftPlantBusinessLogic.MailWorker
{
/// <summary>
/// Реализация абстрактного класса для работы с письмами
/// </summary>
public class MailKitWorker : AbstractMailWorker
{
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
/// <param name="messageInfoLogic"></param>
public MailKitWorker(ILogger<MailKitWorker> logger, IMessageInfoLogic messageInfoLogic, IClientLogic clientLogic) : base(logger, messageInfoLogic, clientLogic) { }
/// <summary>
/// Отправить письмо
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// Получить все письма
/// </summary>
/// <returns></returns>
protected override async Task<List<MessageInfoBindingModel>> ReceiveMailAsync()
{
var list = new List<MessageInfoBindingModel>();
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;
}
}
}

View File

@ -209,5 +209,29 @@ namespace AircraftPlantClientApp.Controllers
var prod = APIClient.GetRequest<PlaneViewModel>($"api/main/getplane?planeId={plane}");
return count * (prod?.Price ?? 1);
}
}
/// <summary>
/// Получение списка писем клиента
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Mails(int page = 1)
{
if (APIClient.Client == null)
{
return Redirect("~/Home/Enter");
}
ViewBag.Page = page;
List<MessageInfoViewModel>? list = APIClient.GetRequest<List<MessageInfoViewModel>>($"api/client/getmessages?clientId={APIClient.Client.Id}&currentPage={page}");
if (list != null && list.Count == 0 && page != 1)
{
page--;
ViewBag.Page = page;
list = APIClient.GetRequest<List<MessageInfoViewModel>>($"api/client/getmessages?clientId={APIClient.Client.Id}&currentPage={page}");
}
return View(list);
}
}
}

View File

@ -0,0 +1,62 @@
@using AircraftPlantContracts.ViewModels
@model List<MessageInfoViewModel>
@{
ViewData["Title"] = "Mails";
}
<div class="text-center">
<h1 class="display-4">Письма</h1>
</div>
<div class="text-center">
@{
if (Model == null)
{
<h3 class="display-4">Авторизируйтесь</h3>
return;
}
<table class="table">
<thead>
<tr>
<th>
Дата письма
</th>
<th>
Заголовок
</th>
<th>
Текст
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.DateDelivery)
</td>
<td>
@Html.DisplayFor(modelItem => item.Subject)
</td>
<td>
@Html.DisplayFor(modelItem => item.Body)
</td>
</tr>
}
</tbody>
</table>
<a href="@Url.Action("Mails", new { page = ViewBag.Page - 1 >= 1 ? ViewBag.Page - 1 : 1 })" class="btn btn-primary">
Назад
</a>
<p>Страница @ViewBag.Page</p>
<a href="@Url.Action("Mails", new { page = ViewBag.Page + 1 })" class="btn btn-primary">
Вперед
</a>
}
</div>

View File

@ -27,6 +27,9 @@
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Личные данные</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Mails">Письма</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Enter">Вход</a>
</li>

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.BindingModels
{
/// <summary>
/// Модель привязки для настройки почтового сервиса
/// </summary>
public class MailConfigBindingModel
{
/// <summary>
/// Логин для доступа к почтовому сервису
/// </summary>
public string MailLogin { get; set; } = string.Empty;
/// <summary>
/// Пароль для доступа к почтовому сервису
/// </summary>
public string MailPassword { get; set; } = string.Empty;
/// <summary>
/// Хост SMTP-клиента
/// </summary>
public string SmtpClientHost { get; set; } = string.Empty;
/// <summary>
/// Порт SMTP-клиента
/// </summary>
public int SmtpClientPort { get; set; }
/// <summary>
/// Хост протокола POP3
/// </summary>
public string PopHost { get; set; } = string.Empty;
/// <summary>
/// Порт протокола POP3
/// </summary>
public int PopPort { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.BindingModels
{
/// <summary>
/// Модель привязки для информации о письме для отправки
/// </summary>
public class MailSendInfoBindingModel
{
/// <summary>
/// Адрес электронной почты
/// </summary>
public string MailAddress { get; set; } = string.Empty;
/// <summary>
/// Заголовок письма
/// </summary>
public string Subject { get; set; } = string.Empty;
/// <summary>
/// Текст письма
/// </summary>
public string Text { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,56 @@
using AircraftPlantDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.BindingModels
{
/// <summary>
/// Модель для передачи данных пользователя
/// в методы для сохранения данных для писем
/// </summary>
public class MessageInfoBindingModel : IMessageInfoModel
{
/// <summary>
/// Идентификатор
/// </summary>
public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Идентификатор клиента
/// </summary>
public int? ClientId { get; set; }
/// <summary>
/// Адрес электронной почты отправителя
/// </summary>
public string SenderName { get; set; } = string.Empty;
/// <summary>
/// Дата получения письма
/// </summary>
public DateTime DateDelivery { get; set; }
/// <summary>
/// Заголовок письма
/// </summary>
public string Subject { get; set; } = string.Empty;
/// <summary>
/// Тело письма
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// Письмо прочитано
/// </summary>
public bool IsChecked { get; set; }
/// <summary>
/// Ответ на писмо
/// </summary>
public string? Reply { get; set; }
}
}

View File

@ -0,0 +1,45 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.BusinessLogicsContracts
{
/// <summary>
/// Интерфейс для описания работы бизнес-логики для писем
/// </summary>
public interface IMessageInfoLogic
{
/// <summary>
/// Получение списка
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model);
/// <summary>
/// Получение отдельной записи
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
MessageInfoViewModel? ReadElement(MessageInfoSearchModel model);
/// <summary>
/// Создание записи
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
bool Create(MessageInfoBindingModel model);
/// <summary>
/// Изменение записи
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
bool Update(MessageInfoBindingModel? model);
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.SearchModels
{
/// <summary>
/// Модель для передачи данных пользователя
/// в методы для поиска данных для писем
/// </summary>
public class MessageInfoSearchModel
{
/// <summary>
/// Идентификатор
/// </summary>
public string? MessageId { get; set; }
/// <summary>
/// Идентификатор клиента
/// </summary>
public int? ClientId { get; set; }
/// <summary>
/// Размер страницы пагинации
/// </summary>
public int? PageSize { get; set; }
/// <summary>
/// Текущая страница пагинации
/// </summary>
public int? CurrentPage { get; set; }
}
}

View File

@ -0,0 +1,51 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.StoragesContracts
{
/// <summary>
/// Интерфейс для описания работы с хранилищем для писем
/// </summary>
public interface IMessageInfoStorage
{
/// <summary>
/// Получение полного списка
/// </summary>
/// <returns></returns>
List<MessageInfoViewModel> GetFullList();
/// <summary>
/// Получение фильтрованного списка
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model);
/// <summary>
/// Получение элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
MessageInfoViewModel? GetElement(MessageInfoSearchModel model);
/// <summary>
/// Добавление элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
MessageInfoViewModel? Insert(MessageInfoBindingModel model);
/// <summary>
/// Редактирование элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
MessageInfoViewModel? Update(MessageInfoBindingModel model);
}
}

View File

@ -0,0 +1,63 @@
using AircraftPlantDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantContracts.ViewModels
{
/// <summary>
/// Модель для передачи данных пользователю
/// для отображения для писем
/// </summary>
public class MessageInfoViewModel : IMessageInfoModel
{
/// <summary>
/// Идентификатор
/// </summary>
public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Идентификатор клиента
/// </summary>
public int? ClientId { get; set; }
/// <summary>
/// Адрес электронной почты отправителя
/// </summary>
[DisplayName("Отправитель")]
public string SenderName { get; set; } = string.Empty;
/// <summary>
/// Дата получения письма
/// </summary>
[DisplayName("Дата письма")]
public DateTime DateDelivery { get; set; }
/// <summary>
/// Заголовок письма
/// </summary>
[DisplayName("Заголовок")]
public string Subject { get; set; } = string.Empty;
/// <summary>
/// Тело письма
/// </summary>
[DisplayName("Текст")]
public string Body { get; set; } = string.Empty;
/// <summary>
/// Письмо прочитано
/// </summary>
[DisplayName("Прочитано")]
public bool IsChecked { get; set; }
/// <summary>
/// Ответ на письмо
/// </summary>
[DisplayName("Ответ")]
public string? Reply { get; set; }
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantDataModels.Models
{
/// <summary>
/// Интерфейс для модели письма
/// </summary>
public interface IMessageInfoModel
{
/// <summary>
/// Идентификатор
/// </summary>
string MessageId { get; }
/// <summary>
/// Идентификатор клиента
/// </summary>
int? ClientId { get; }
/// <summary>
/// Адрес электронной почты отправителя
/// </summary>
string SenderName { get; }
/// <summary>
/// Дата получения письма
/// </summary>
DateTime DateDelivery { get; }
/// <summary>
/// Заголовок письма
/// </summary>
string Subject { get; }
/// <summary>
/// Тело письма
/// </summary>
string Body { get; }
/// <summary>
/// Письмо прочитано
/// </summary>
bool IsChecked { get; }
/// <summary>
/// Ответ на письмо
/// </summary>
string? Reply { get; }
}
}

View File

@ -65,5 +65,10 @@ namespace AircraftPlantDatabaseImplement
/// Таблица исполнителей
/// </summary>
public virtual DbSet<Implementer> Implementers { set; get; }
}
/// <summary>
/// Таблица писем
/// </summary>
public virtual DbSet<Message> Messages { set; get; }
}
}

View File

@ -0,0 +1,127 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.StoragesContracts;
using AircraftPlantContracts.ViewModels;
using AircraftPlantDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantDatabaseImplement.Implements
{
/// <summary>
/// Реализация интерфейса хранилища для писем
/// </summary>
public class MessageInfoStorage : IMessageInfoStorage
{
/// <summary>
/// Получение полного списка
/// </summary>
/// <returns></returns>
public List<MessageInfoViewModel> GetFullList()
{
using var context = new AircraftPlantDatabase();
return context.Messages
.Select(x => x.GetViewModel)
.ToList();
}
/// <summary>
/// Получение фильтрованного списка
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
if (!model.ClientId.HasValue && (!model.PageSize.HasValue || !model.CurrentPage.HasValue))
{
return new();
}
using var context = new AircraftPlantDatabase();
if (model.CurrentPage.HasValue && model.PageSize.HasValue && model.ClientId.HasValue)
{
return context.Messages
.Where(x => x.ClientId == model.ClientId)
.Skip((model.CurrentPage.Value - 1) * model.PageSize.Value)
.Take(model.PageSize.Value)
.Select(x => x.GetViewModel)
.ToList();
}
if (model.CurrentPage.HasValue && model.PageSize.HasValue)
{
return context.Messages
.Skip((model.CurrentPage.Value - 1) * model.PageSize.Value)
.Take(model.PageSize.Value)
.Select(x => x.GetViewModel)
.ToList();
}
return context.Messages
.Where(x => x.ClientId == model.ClientId)
.Select(x => x.GetViewModel)
.ToList();
}
/// <summary>
/// Получение элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if (string.IsNullOrEmpty(model.MessageId))
{
return null;
}
using var context = new AircraftPlantDatabase();
return context.Messages
.FirstOrDefault(x => x.MessageId == model.MessageId)
?.GetViewModel;
}
/// <summary>
/// Добавление элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
var newMessage = Message.Create(model);
if (newMessage == null)
{
return null;
}
using var context = new AircraftPlantDatabase();
context.Messages.Add(newMessage);
context.SaveChanges();
return newMessage.GetViewModel;
}
/// <summary>
/// Редактирование элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
using var context = new AircraftPlantDatabase();
var message = context.Messages.FirstOrDefault(x => x.MessageId == model.MessageId);
if (message == null)
{
return null;
}
message.Update(model);
context.SaveChanges();
return message.GetViewModel;
}
}
}

View File

@ -0,0 +1,298 @@
// <auto-generated />
using System;
using AircraftPlantDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AircraftPlantDatabaseImplement.Migrations
{
[DbContext(typeof(AircraftPlantDatabase))]
[Migration("20240504174710_MessageInfoCreate")]
partial class MessageInfoCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Clients");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Component", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ComponentName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Cost")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Components");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Implementer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ImplementerFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("Qualification")
.HasColumnType("int");
b.Property<int>("WorkExperience")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Implementers");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Message", b =>
{
b.Property<string>("MessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("Body")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("DateDelivery")
.HasColumnType("datetime2");
b.Property<string>("SenderName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Subject")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.ToTable("Messages");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<int?>("ImplementerId")
.HasColumnType("int");
b.Property<int>("PlaneId")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<double>("Sum")
.HasColumnType("float");
b.HasKey("Id");
b.HasIndex("ClientId");
b.HasIndex("ImplementerId");
b.HasIndex("PlaneId");
b.ToTable("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Plane", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("PlaneName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Planes");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.PlaneComponent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ComponentId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("PlaneId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ComponentId");
b.HasIndex("PlaneId");
b.ToTable("PlaneComponents");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Message", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Order", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Client", "Client")
.WithMany("Orders")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AircraftPlantDatabaseImplement.Models.Implementer", "Implementer")
.WithMany("Orders")
.HasForeignKey("ImplementerId");
b.HasOne("AircraftPlantDatabaseImplement.Models.Plane", "Plane")
.WithMany("Orders")
.HasForeignKey("PlaneId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
b.Navigation("Implementer");
b.Navigation("Plane");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.PlaneComponent", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Component", "Component")
.WithMany("PlaneComponents")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AircraftPlantDatabaseImplement.Models.Plane", "Plane")
.WithMany("Components")
.HasForeignKey("PlaneId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Plane");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Component", b =>
{
b.Navigation("PlaneComponents");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Implementer", b =>
{
b.Navigation("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Plane", b =>
{
b.Navigation("Components");
b.Navigation("Orders");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AircraftPlantDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class MessageInfoCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Messages",
columns: table => new
{
MessageId = table.Column<string>(type: "nvarchar(450)", nullable: false),
ClientId = table.Column<int>(type: "int", nullable: true),
SenderName = table.Column<string>(type: "nvarchar(max)", nullable: false),
DateDelivery = table.Column<DateTime>(type: "datetime2", nullable: false),
Subject = table.Column<string>(type: "nvarchar(max)", nullable: false),
Body = table.Column<string>(type: "nvarchar(max)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Messages", x => x.MessageId);
table.ForeignKey(
name: "FK_Messages_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_Messages_ClientId",
table: "Messages",
column: "ClientId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Messages");
}
}
}

View File

@ -0,0 +1,381 @@
// <auto-generated />
using System;
using AircraftPlantDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AircraftPlantDatabaseImplement.Migrations
{
[DbContext(typeof(AircraftPlantDatabase))]
[Migration("20240505220907_MessageInfoUpdate")]
partial class MessageInfoUpdate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Clients");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Component", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ComponentName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Cost")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Components");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Implementer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ImplementerFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("Qualification")
.HasColumnType("int");
b.Property<int>("WorkExperience")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Implementers");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Message", b =>
{
b.Property<string>("MessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("Body")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("DateDelivery")
.HasColumnType("datetime2");
b.Property<bool>("IsChecked")
.HasColumnType("bit");
b.Property<string>("Reply")
.HasColumnType("nvarchar(max)");
b.Property<string>("SenderName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Subject")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.ToTable("Messages");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<int?>("ImplementerId")
.HasColumnType("int");
b.Property<int>("PlaneId")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<double>("Sum")
.HasColumnType("float");
b.HasKey("Id");
b.HasIndex("ClientId");
b.HasIndex("ImplementerId");
b.HasIndex("PlaneId");
b.ToTable("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Plane", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("PlaneName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Planes");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.PlaneComponent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ComponentId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("PlaneId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ComponentId");
b.HasIndex("PlaneId");
b.ToTable("PlaneComponents");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("DateOpening")
.HasColumnType("datetime2");
b.Property<int>("MaxPlanes")
.HasColumnType("int");
b.Property<string>("ShopName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.ShopPlane", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("PlaneId")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PlaneId");
b.HasIndex("ShopId");
b.ToTable("ShopPlanes");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Message", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Order", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Client", "Client")
.WithMany("Orders")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AircraftPlantDatabaseImplement.Models.Implementer", "Implementer")
.WithMany("Orders")
.HasForeignKey("ImplementerId");
b.HasOne("AircraftPlantDatabaseImplement.Models.Plane", "Plane")
.WithMany("Orders")
.HasForeignKey("PlaneId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
b.Navigation("Implementer");
b.Navigation("Plane");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.PlaneComponent", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Component", "Component")
.WithMany("PlaneComponents")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AircraftPlantDatabaseImplement.Models.Plane", "Plane")
.WithMany("Components")
.HasForeignKey("PlaneId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Plane");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.ShopPlane", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Plane", "Plane")
.WithMany()
.HasForeignKey("PlaneId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AircraftPlantDatabaseImplement.Models.Shop", "Shop")
.WithMany("Planes")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Plane");
b.Navigation("Shop");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Component", b =>
{
b.Navigation("PlaneComponents");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Implementer", b =>
{
b.Navigation("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Plane", b =>
{
b.Navigation("Components");
b.Navigation("Orders");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Planes");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AircraftPlantDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class MessageInfoUpdate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsChecked",
table: "Messages",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "Reply",
table: "Messages",
type: "nvarchar(max)",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsChecked",
table: "Messages");
migrationBuilder.DropColumn(
name: "Reply",
table: "Messages");
}
}
}

View File

@ -94,6 +94,42 @@ namespace AircraftPlantDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Message", b =>
{
b.Property<string>("MessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("Body")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("DateDelivery")
.HasColumnType("datetime2");
b.Property<bool>("IsChecked")
.HasColumnType("bit");
b.Property<string>("Reply")
.HasColumnType("nvarchar(max)");
b.Property<string>("SenderName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Subject")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.ToTable("Messages");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -236,6 +272,15 @@ namespace AircraftPlantDatabaseImplement.Migrations
b.ToTable("ShopPlanes");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Message", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Order", b =>
{
b.HasOne("AircraftPlantDatabaseImplement.Models.Client", "Client")
@ -301,6 +346,8 @@ namespace AircraftPlantDatabaseImplement.Migrations
modelBuilder.Entity("AircraftPlantDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});

View File

@ -45,12 +45,18 @@ namespace AircraftPlantDatabaseImplement.Models
[ForeignKey("ClientId")]
public virtual List<Order> Orders { get; set; } = new();
/// <summary>
/// Создание модели клиента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static Client? Create(ClientBindingModel model)
/// <summary>
/// Связь с письмами
/// </summary>
[ForeignKey("ClientId")]
public virtual List<Message> Messages { get; set; } = new();
/// <summary>
/// Создание модели клиента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static Client? Create(ClientBindingModel model)
{
if (model == null)
{

View File

@ -0,0 +1,124 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.ViewModels;
using AircraftPlantDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantDatabaseImplement.Models
{
/// <summary>
/// Сущность "Письмо"
/// </summary>
public class Message : IMessageInfoModel
{
/// <summary>
/// Идентификатор
/// </summary>
[Key]
public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Идентификатор клиента
/// </summary>
public int? ClientId { get; set; }
/// <summary>
/// Сущность "Клиент"
/// </summary>
public virtual Client? Client { get; set; }
/// <summary>
/// Адрес электронной почты отправителя
/// </summary>
[Required]
public string SenderName { get; set; } = string.Empty;
/// <summary>
/// Дата получения письма
/// </summary>
[Required]
public DateTime DateDelivery { get; set; }
/// <summary>
/// Заголовок письма
/// </summary>
[Required]
public string Subject { get; set; } = string.Empty;
/// <summary>
/// Тело письма
/// </summary>
[Required]
public string Body { get; set; } = string.Empty;
/// <summary>
/// Письмо прочитано
/// </summary>
[Required]
public bool IsChecked { get; set; }
/// <summary>
/// Ответ на писмо
/// </summary>
public string? Reply { get; set; }
/// <summary>
/// Создание модели письма
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static Message? 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,
IsChecked = model.IsChecked,
Reply = model.Reply
};
}
/// <summary>
/// Изменение модели письма
/// </summary>
/// <param name="model"></param>
public void Update(MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
IsChecked = model.IsChecked;
Reply = model.Reply;
}
/// <summary>
/// Получение модели письма
/// </summary>
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
IsChecked = IsChecked,
Reply = Reply
};
}
}

View File

@ -48,10 +48,15 @@ namespace AircraftPlantFileImplement
/// </summary>
private readonly string ImplementerFileName = "Implementer.xml";
/// <summary>
/// Список классов-моделей компонентов
/// </summary>
public List<Component> Components { get; set; }
/// <summary>
/// Название файла для хранения информации о письмах
/// </summary>
private readonly string MessageFileName = "Message.xml";
/// <summary>
/// Список классов-моделей компонентов
/// </summary>
public List<Component> Components { get; set; }
/// <summary>
/// Список классов-моделей заказов
@ -78,10 +83,15 @@ namespace AircraftPlantFileImplement
/// </summary>
public List<Implementer> Implementers { get; set; }
/// <summary>
/// Конструктор
/// </summary>
private DataFileSingleton()
/// <summary>
/// Список классов-моделей писем
/// </summary>
public List<Message> Messages { get; set; }
/// <summary>
/// Конструктор
/// </summary>
private DataFileSingleton()
{
Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!;
Planes = LoadData(PlaneFileName, "Plane", x => Plane.Create(x)!)!;
@ -89,6 +99,7 @@ namespace AircraftPlantFileImplement
Shops = LoadData(ShopFileName, "Shop", x => Shop.Create(x)!)!;
Clients = LoadData(ClientFileName, "Client", x => Client.Create(x)!)!;
Implementers = LoadData(ImplementerFileName, "Implementer", x => Implementer.Create(x)!)!;
Messages = LoadData(MessageFileName, "Message", x => Message.Create(x)!)!;
}
/// <summary>
@ -134,15 +145,20 @@ namespace AircraftPlantFileImplement
/// </summary>
public void SaveImplementers() => SaveData(Implementers, ImplementerFileName, "Implementers", x => x.GetXElement);
/// <summary>
/// Метод для загрузки данных из xml-файла
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="filename"></param>
/// <param name="xmlNodeName"></param>
/// <param name="selectFunction"></param>
/// <returns></returns>
private static List<T>? LoadData<T>(string filename, string xmlNodeName, Func<XElement, T> selectFunction)
/// <summary>
/// Сохранение писем
/// </summary>
public void SaveMessages() => SaveData(Messages, MessageFileName, "Messages", x => x.GetXElement);
/// <summary>
/// Метод для загрузки данных из xml-файла
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="filename"></param>
/// <param name="xmlNodeName"></param>
/// <param name="selectFunction"></param>
/// <returns></returns>
private static List<T>? LoadData<T>(string filename, string xmlNodeName, Func<XElement, T> selectFunction)
{
if (File.Exists(filename))
{

View File

@ -0,0 +1,133 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.StoragesContracts;
using AircraftPlantContracts.ViewModels;
using AircraftPlantFileImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantFileImplement.Implements
{
/// <summary>
/// Реализация интерфейса хранилища для писем
/// </summary>
public class MessageInfoStorage : IMessageInfoStorage
{
/// <summary>
/// Хранилище
/// </summary>
private readonly DataFileSingleton _source;
/// <summary>
/// Конструктор
/// </summary>
public MessageInfoStorage()
{
_source = DataFileSingleton.GetInstance();
}
/// <summary>
/// Получение полного списка
/// </summary>
/// <returns></returns>
public List<MessageInfoViewModel> GetFullList()
{
return _source.Messages
.Select(x => x.GetViewModel)
.ToList();
}
/// <summary>
/// Получение фильтрованного списка
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
if (!model.ClientId.HasValue && (!model.PageSize.HasValue || !model.CurrentPage.HasValue))
{
return new();
}
if (model.CurrentPage.HasValue && model.PageSize.HasValue && model.ClientId.HasValue)
{
return _source.Messages
.Where(x => x.ClientId == model.ClientId)
.Skip((model.CurrentPage.Value - 1) * model.PageSize.Value)
.Take(model.PageSize.Value)
.Select(x => x.GetViewModel)
.ToList();
}
if (model.CurrentPage.HasValue && model.PageSize.HasValue)
{
return _source.Messages
.Skip((model.CurrentPage.Value - 1) * model.PageSize.Value)
.Take(model.PageSize.Value)
.Select(x => x.GetViewModel)
.ToList();
}
return _source.Messages
.Where(x => x.ClientId == model.ClientId)
.Select(x => x.GetViewModel)
.ToList();
}
/// <summary>
/// Получение элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if (string.IsNullOrEmpty(model.MessageId))
{
return null;
}
return _source.Messages
.FirstOrDefault(x => x.MessageId == model.MessageId)
?.GetViewModel;
}
/// <summary>
/// Добавление элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
var newMessage = Message.Create(model);
if (newMessage == null)
{
return null;
}
_source.Messages.Add(newMessage);
_source.SaveMessages();
return newMessage.GetViewModel;
}
/// <summary>
/// Редактирование элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
var message = _source.Messages.FirstOrDefault(x => x.MessageId == model.MessageId);
if (message == null)
{
return null;
}
message.Update(model);
_source.SaveMessages();
return message.GetViewModel;
}
}
}

View File

@ -0,0 +1,151 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.ViewModels;
using AircraftPlantDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace AircraftPlantFileImplement.Models
{
/// <summary>
/// Сущность "Письмо"
/// </summary>
public class Message : IMessageInfoModel
{
/// <summary>
/// Идентификатор
/// </summary>
public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Идентификатор клиента
/// </summary>
public int? ClientId { get; set; }
/// <summary>
/// Адрес электронной почты отправителя
/// </summary>
public string SenderName { get; set; } = string.Empty;
/// <summary>
/// Дата получения письма
/// </summary>
public DateTime DateDelivery { get; set; }
/// <summary>
/// Заголовок письма
/// </summary>
public string Subject { get; set; } = string.Empty;
/// <summary>
/// Тело письма
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// Письмо прочитано
/// </summary>
public bool IsChecked { get; set; }
/// <summary>
/// Ответ на писмо
/// </summary>
public string? Reply { get; set; }
/// <summary>
/// Создание модели письма
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static Message? 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,
IsChecked = model.IsChecked,
Reply = model.Reply
};
}
/// <summary>
/// Создание модели письма из данных файла
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
public static Message? Create(XElement element)
{
if (element == null)
{
return null;
}
return new()
{
MessageId = element.Attribute("MessageId")!.Value,
ClientId = Convert.ToInt32(element.Attribute("ClientId")!.Value),
SenderName = element.Attribute("SenderName")!.Value,
DateDelivery = Convert.ToDateTime(element.Attribute("DateDelivery")!.Value),
Subject = element.Attribute("Subject")!.Value,
Body = element.Attribute("Body")!.Value,
IsChecked = Convert.ToBoolean(element.Attribute("IsChecked")!.Value),
Reply = element.Attribute("Reply")!.Value
};
}
/// <summary>
/// Изменение модели письма
/// </summary>
/// <param name="model"></param>
public void Update(MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
IsChecked = model.IsChecked;
Reply = model.Reply;
}
/// <summary>
/// Получение модели письма
/// </summary>
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
IsChecked = IsChecked,
Reply = Reply
};
/// <summary>
/// Запись данных о модели письма в файл
/// </summary>
public XElement GetXElement => new("MessageInfo",
new XAttribute("MessageId", MessageId),
new XAttribute("ClientId", ClientId),
new XAttribute("SenderName", SenderName),
new XAttribute("DateDelivery", DateDelivery),
new XAttribute("Subject", Subject),
new XAttribute("Body", Body),
new XAttribute("IsChecked", IsChecked),
new XAttribute("Reply", Reply));
}
}

View File

@ -47,10 +47,15 @@ namespace AircraftPlantListImplement
/// </summary>
public List<Implementer> Implementers { get; set; }
/// <summary>
/// Конструктор
/// </summary>
private DataListSingleton()
/// <summary>
/// Список классов-моделей писем
/// </summary>
public List<Message> Messages { get; set; }
/// <summary>
/// Конструктор
/// </summary>
private DataListSingleton()
{
Components = new List<Component>();
Orders = new List<Order>();
@ -58,6 +63,7 @@ namespace AircraftPlantListImplement
Shops = new List<Shop>();
Clients = new List<Client>();
Implementers = new List<Implementer>();
Messages = new List<Message>();
}
/// <summary>

View File

@ -0,0 +1,145 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.StoragesContracts;
using AircraftPlantContracts.ViewModels;
using AircraftPlantListImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantListImplement.Implements
{
/// <summary>
/// Реализация интерфейса хранилища для писем
/// </summary>
public class MessageInfoStorage : IMessageInfoStorage
{
/// <summary>
/// Хранилище
/// </summary>
private readonly DataListSingleton _source;
/// <summary>
/// Конструктор
/// </summary>
public MessageInfoStorage()
{
_source = DataListSingleton.GetInstance();
}
/// <summary>
/// Получение полного списка
/// </summary>
/// <returns></returns>
public List<MessageInfoViewModel> GetFullList()
{
var result = new List<MessageInfoViewModel>();
foreach (var message in _source.Messages)
{
result.Add(message.GetViewModel);
}
return result;
}
/// <summary>
/// Получение фильтрованного списка
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
var result = new List<MessageInfoViewModel>();
if (model.ClientId.HasValue)
{
foreach (var message in _source.Messages)
{
if (message.ClientId == model.ClientId)
{
result.Add(message.GetViewModel);
}
}
return result;
}
if (!model.CurrentPage.HasValue || !model.PageSize.HasValue)
{
return result;
}
var resultPages = new List<MessageInfoViewModel>();
if (model.ClientId.HasValue)
{
for (int i = (model.CurrentPage.Value - 1) * model.PageSize.Value; i < model.PageSize.Value * model.CurrentPage.Value; i++)
{
resultPages.Add(result[i]);
}
}
else
{
for (int i = (model.CurrentPage.Value - 1) * model.PageSize.Value; i < model.PageSize.Value * model.CurrentPage.Value; i++)
{
resultPages.Add(_source.Messages[i].GetViewModel);
}
}
return result;
}
/// <summary>
/// Получение элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Добавление элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
var newMessage = Message.Create(model);
if (newMessage == null)
{
return null;
}
_source.Messages.Add(newMessage);
return newMessage.GetViewModel;
}
/// <summary>
/// Редактирование элемента
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
foreach (var message in _source.Messages)
{
if (message.MessageId == model.MessageId)
{
message.Update(model);
return message.GetViewModel;
}
}
return null;
}
}
}

View File

@ -0,0 +1,112 @@
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.ViewModels;
using AircraftPlantDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantListImplement.Models
{
/// <summary>
/// Сущность "Письмо"
/// </summary>
public class Message : IMessageInfoModel
{
/// <summary>
/// Идентификатор
/// </summary>
public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Идентификатор клиента
/// </summary>
public int? ClientId { get; set; }
/// <summary>
/// Адрес электронной почты отправителя
/// </summary>
public string SenderName { get; set; } = string.Empty;
/// <summary>
/// Дата получения письма
/// </summary>
public DateTime DateDelivery { get; set; }
/// <summary>
/// Заголовок письма
/// </summary>
public string Subject { get; set; } = string.Empty;
/// <summary>
/// Тело письма
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// Письмо прочитано
/// </summary>
public bool IsChecked { get; set; }
/// <summary>
/// Ответ на писмо
/// </summary>
public string? Reply { get; set; }
/// <summary>
/// Создание модели письма
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static Message? 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,
IsChecked = model.IsChecked,
Reply = model.Reply
};
}
/// <summary>
/// Изменение модели письма
/// </summary>
/// <param name="model"></param>
public void Update(MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
IsChecked = model.IsChecked;
Reply = model.Reply;
}
/// <summary>
/// Получение модели письма
/// </summary>
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
IsChecked = IsChecked,
Reply = Reply
};
}
}

View File

@ -23,15 +23,22 @@ namespace AircraftPlantRestApi.Controllers
/// </summary>
private readonly IClientLogic _logic;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logic"></param>
/// <param name="logger"></param>
public ClientController(IClientLogic logic, ILogger<ClientController> logger)
/// <summary>
/// Бизнес-логика для писем
/// </summary>
private readonly IMessageInfoLogic _mailLogic;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logic"></param>
/// <param name="logger"></param>
/// <param name="mailLogic"></param>
public ClientController(IClientLogic logic, ILogger<ClientController> logger, IMessageInfoLogic mailLogic)
{
_logger = logger;
_logic = logic;
_mailLogic = mailLogic;
}
/// <summary>
@ -93,5 +100,37 @@ namespace AircraftPlantRestApi.Controllers
throw;
}
}
}
/// <summary>
/// Получение списка писем клиента
/// </summary>
/// <param name="clientId"></param>
/// <returns></returns>
[HttpGet]
public List<MessageInfoViewModel>? GetMessages(int clientId, int? currentPage)
{
try
{
if (currentPage == null)
{
return _mailLogic.ReadList(new MessageInfoSearchModel
{
ClientId = clientId
});
}
return _mailLogic.ReadList(new MessageInfoSearchModel
{
ClientId = clientId,
CurrentPage = currentPage,
PageSize = 3
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения писем клиента");
throw;
}
}
}
}

View File

@ -1,4 +1,6 @@
using AircraftPlantBusinessLogic.BusinessLogics;
using AircraftPlantBusinessLogic.MailWorker;
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.StoragesContracts;
using AircraftPlantDatabaseImplement.Implements;
@ -15,12 +17,16 @@ builder.Services.AddTransient<IImplementerStorage, ImplementerStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<IPlaneStorage, PlaneStorage>();
builder.Services.AddTransient<IShopStorage, ShopStorage>();
builder.Services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<IImplementerLogic, ImplementerLogic>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IPlaneLogic, PlaneLogic>();
builder.Services.AddTransient<IShopLogic, ShopLogic>();
builder.Services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
builder.Services.AddSingleton<AbstractMailWorker, MailKitWorker>();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@ -32,6 +38,18 @@ builder.Services.AddSwaggerGen(c =>
var app = builder.Build();
// Íàñòðîéêà äëÿ îòïðàâêè ïèñåì
var mailSender = app.Services.GetService<AbstractMailWorker>();
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())
{

View File

@ -5,5 +5,12 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"SmtpClientHost": "smtp.gmail.com",
"SmtpClientPort": "587",
"PopHost": "pop.gmail.com",
"PopPort": "995",
"MailLogin": "aircraftplant73@gmail.com",
"MailPassword": "vcus klnn auqe axlq"
}

View File

@ -37,4 +37,10 @@
<ProjectReference Include="..\AircraftPlantListImplement\AircraftPlantListImplement.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="App.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SmtpClientHost" value="smtp.gmail.com" />
<add key="SmtpClientPort" value="587" />
<add key="PopHost" value="pop.gmail.com" />
<add key="PopPort" value="995" />
<add key="MailLogin" value="aircraftplant73@gmail.com" />
<add key="MailPassword" value="vcus klnn auqe axlq" />
</appSettings>
</configuration>

View File

@ -20,139 +20,139 @@
base.Dispose(disposing);
}
#region Windows Form Designer generated code
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
textBoxImplementerFIO = new TextBox();
textBoxPassword = new TextBox();
numericUpDownWorkExperience = new NumericUpDown();
numericUpDownQualification = new NumericUpDown();
buttonCancel = new Button();
labelImplementerFIO = new Label();
labelPassword = new Label();
labelWorkExperience = new Label();
labelQualification = new Label();
buttonSave = new Button();
((System.ComponentModel.ISupportInitialize)numericUpDownWorkExperience).BeginInit();
((System.ComponentModel.ISupportInitialize)numericUpDownQualification).BeginInit();
SuspendLayout();
//
// textBoxImplementerFIO
//
textBoxImplementerFIO.Location = new Point(108, 12);
textBoxImplementerFIO.Name = "textBoxImplementerFIO";
textBoxImplementerFIO.Size = new Size(264, 23);
textBoxImplementerFIO.TabIndex = 0;
//
// textBoxPassword
//
textBoxPassword.Location = new Point(108, 41);
textBoxPassword.Name = "textBoxPassword";
textBoxPassword.Size = new Size(264, 23);
textBoxPassword.TabIndex = 1;
//
// numericUpDownWorkExperience
//
numericUpDownWorkExperience.Location = new Point(108, 70);
numericUpDownWorkExperience.Name = "numericUpDownWorkExperience";
numericUpDownWorkExperience.Size = new Size(264, 23);
numericUpDownWorkExperience.TabIndex = 2;
//
// numericUpDownQualification
//
numericUpDownQualification.Location = new Point(108, 99);
numericUpDownQualification.Name = "numericUpDownQualification";
numericUpDownQualification.Size = new Size(264, 23);
numericUpDownQualification.TabIndex = 3;
//
// buttonCancel
//
buttonCancel.Location = new Point(297, 134);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(75, 23);
buttonCancel.TabIndex = 4;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// labelImplementerFIO
//
labelImplementerFIO.AutoSize = true;
labelImplementerFIO.Location = new Point(12, 15);
labelImplementerFIO.Name = "labelImplementerFIO";
labelImplementerFIO.Size = new Size(37, 15);
labelImplementerFIO.TabIndex = 5;
labelImplementerFIO.Text = "ФИО:";
//
// labelPassword
//
labelPassword.AutoSize = true;
labelPassword.Location = new Point(11, 44);
labelPassword.Name = "labelPassword";
labelPassword.Size = new Size(52, 15);
labelPassword.TabIndex = 6;
labelPassword.Text = "Пароль:";
//
// labelWorkExperience
//
labelWorkExperience.AutoSize = true;
labelWorkExperience.Location = new Point(12, 72);
labelWorkExperience.Name = "labelWorkExperience";
labelWorkExperience.Size = new Size(38, 15);
labelWorkExperience.TabIndex = 7;
labelWorkExperience.Text = "label1";
//
// labelQualification
//
labelQualification.AutoSize = true;
labelQualification.Location = new Point(11, 101);
labelQualification.Name = "labelQualification";
labelQualification.Size = new Size(91, 15);
labelQualification.TabIndex = 8;
labelQualification.Text = "Квалификация:";
//
// buttonSave
//
buttonSave.Location = new Point(216, 134);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(75, 23);
buttonSave.TabIndex = 9;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// FormImplementer
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(384, 169);
Controls.Add(buttonSave);
Controls.Add(labelQualification);
Controls.Add(labelWorkExperience);
Controls.Add(labelPassword);
Controls.Add(labelImplementerFIO);
Controls.Add(buttonCancel);
Controls.Add(numericUpDownQualification);
Controls.Add(numericUpDownWorkExperience);
Controls.Add(textBoxPassword);
Controls.Add(textBoxImplementerFIO);
Name = "FormImplementer";
Text = "Исполнитель";
Load += FormImplementer_Load;
((System.ComponentModel.ISupportInitialize)numericUpDownWorkExperience).EndInit();
((System.ComponentModel.ISupportInitialize)numericUpDownQualification).EndInit();
ResumeLayout(false);
PerformLayout();
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
textBoxImplementerFIO = new TextBox();
textBoxPassword = new TextBox();
numericUpDownWorkExperience = new NumericUpDown();
numericUpDownQualification = new NumericUpDown();
buttonCancel = new Button();
labelImplementerFIO = new Label();
labelPassword = new Label();
labelWorkExperience = new Label();
labelQualification = new Label();
buttonSave = new Button();
((System.ComponentModel.ISupportInitialize)numericUpDownWorkExperience).BeginInit();
((System.ComponentModel.ISupportInitialize)numericUpDownQualification).BeginInit();
SuspendLayout();
//
// textBoxImplementerFIO
//
textBoxImplementerFIO.Location = new Point(108, 12);
textBoxImplementerFIO.Name = "textBoxImplementerFIO";
textBoxImplementerFIO.Size = new Size(264, 23);
textBoxImplementerFIO.TabIndex = 0;
//
// textBoxPassword
//
textBoxPassword.Location = new Point(108, 41);
textBoxPassword.Name = "textBoxPassword";
textBoxPassword.Size = new Size(264, 23);
textBoxPassword.TabIndex = 1;
//
// numericUpDownWorkExperience
//
numericUpDownWorkExperience.Location = new Point(108, 70);
numericUpDownWorkExperience.Name = "numericUpDownWorkExperience";
numericUpDownWorkExperience.Size = new Size(264, 23);
numericUpDownWorkExperience.TabIndex = 2;
//
// numericUpDownQualification
//
numericUpDownQualification.Location = new Point(108, 99);
numericUpDownQualification.Name = "numericUpDownQualification";
numericUpDownQualification.Size = new Size(264, 23);
numericUpDownQualification.TabIndex = 3;
//
// buttonCancel
//
buttonCancel.Location = new Point(297, 134);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(75, 23);
buttonCancel.TabIndex = 4;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// labelImplementerFIO
//
labelImplementerFIO.AutoSize = true;
labelImplementerFIO.Location = new Point(12, 15);
labelImplementerFIO.Name = "labelImplementerFIO";
labelImplementerFIO.Size = new Size(37, 15);
labelImplementerFIO.TabIndex = 5;
labelImplementerFIO.Text = "ФИО:";
//
// labelPassword
//
labelPassword.AutoSize = true;
labelPassword.Location = new Point(11, 44);
labelPassword.Name = "labelPassword";
labelPassword.Size = new Size(52, 15);
labelPassword.TabIndex = 6;
labelPassword.Text = "Пароль:";
//
// labelWorkExperience
//
labelWorkExperience.AutoSize = true;
labelWorkExperience.Location = new Point(12, 72);
labelWorkExperience.Name = "labelWorkExperience";
labelWorkExperience.Size = new Size(84, 15);
labelWorkExperience.TabIndex = 7;
labelWorkExperience.Text = "Опыт работы:";
//
// labelQualification
//
labelQualification.AutoSize = true;
labelQualification.Location = new Point(11, 101);
labelQualification.Name = "labelQualification";
labelQualification.Size = new Size(91, 15);
labelQualification.TabIndex = 8;
labelQualification.Text = "Квалификация:";
//
// buttonSave
//
buttonSave.Location = new Point(216, 134);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(75, 23);
buttonSave.TabIndex = 9;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// FormImplementer
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(384, 169);
Controls.Add(buttonSave);
Controls.Add(labelQualification);
Controls.Add(labelWorkExperience);
Controls.Add(labelPassword);
Controls.Add(labelImplementerFIO);
Controls.Add(buttonCancel);
Controls.Add(numericUpDownQualification);
Controls.Add(numericUpDownWorkExperience);
Controls.Add(textBoxPassword);
Controls.Add(textBoxImplementerFIO);
Name = "FormImplementer";
Text = "Исполнитель";
Load += FormImplementer_Load;
((System.ComponentModel.ISupportInitialize)numericUpDownWorkExperience).EndInit();
((System.ComponentModel.ISupportInitialize)numericUpDownQualification).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
#endregion
private TextBox textBoxImplementerFIO;
private TextBox textBoxImplementerFIO;
private TextBox textBoxPassword;
private NumericUpDown numericUpDownWorkExperience;
private NumericUpDown numericUpDownQualification;

View File

@ -0,0 +1,122 @@
namespace AircraftPlantView
{
partial class FormMail
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
dataGridView = new DataGridView();
buttonPrev = new Button();
labelPage = new Label();
buttonNext = new Button();
buttonReply = new Button();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
//
// dataGridView
//
dataGridView.AllowUserToAddRows = false;
dataGridView.AllowUserToDeleteRows = false;
dataGridView.BackgroundColor = Color.White;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Dock = DockStyle.Top;
dataGridView.GridColor = Color.Black;
dataGridView.Location = new Point(0, 0);
dataGridView.MultiSelect = false;
dataGridView.Name = "dataGridView";
dataGridView.ReadOnly = true;
dataGridView.RowHeadersVisible = false;
dataGridView.RowTemplate.Height = 25;
dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView.Size = new Size(584, 320);
dataGridView.TabIndex = 2;
//
// buttonPrev
//
buttonPrev.Location = new Point(12, 326);
buttonPrev.Name = "buttonPrev";
buttonPrev.Size = new Size(75, 23);
buttonPrev.TabIndex = 3;
buttonPrev.Text = "<<<";
buttonPrev.UseVisualStyleBackColor = true;
buttonPrev.Click += buttonPrev_Click;
//
// labelPage
//
labelPage.AutoSize = true;
labelPage.Location = new Point(93, 330);
labelPage.Name = "labelPage";
labelPage.Size = new Size(69, 15);
labelPage.TabIndex = 4;
labelPage.Text = "Страница 1";
//
// buttonNext
//
buttonNext.Location = new Point(168, 326);
buttonNext.Name = "buttonNext";
buttonNext.Size = new Size(75, 23);
buttonNext.TabIndex = 5;
buttonNext.Text = ">>>";
buttonNext.UseVisualStyleBackColor = true;
buttonNext.Click += buttonNext_Click;
//
// buttonReply
//
buttonReply.Location = new Point(497, 330);
buttonReply.Name = "buttonReply";
buttonReply.Size = new Size(75, 23);
buttonReply.TabIndex = 6;
buttonReply.Text = "Ответить";
buttonReply.UseVisualStyleBackColor = true;
buttonReply.Click += buttonReply_Click;
//
// FormMail
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(584, 361);
Controls.Add(buttonReply);
Controls.Add(buttonNext);
Controls.Add(labelPage);
Controls.Add(buttonPrev);
Controls.Add(dataGridView);
Name = "FormMail";
Text = "Письма";
Load += FormMail_Load;
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private DataGridView dataGridView;
private Button buttonPrev;
private Label labelPage;
private Button buttonNext;
private Button buttonReply;
}
}

View File

@ -0,0 +1,152 @@
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.SearchModels;
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 AircraftPlantView
{
/// <summary>
/// Форма для вывода писем
/// </summary>
public partial class FormMail : Form
{
/// <summary>
/// Логгер
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Бизнес-логика для писем
/// </summary>
private readonly IMessageInfoLogic _logic;
/// <summary>
/// Размер страницы пагинации
/// </summary>
private int PageSize = 3;
/// <summary>
/// Текущая страница пагинации
/// </summary>
private int CurrentPage = 1;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
/// <param name="logic"></param>
public FormMail(ILogger<FormMail> logger, IMessageInfoLogic logic)
{
InitializeComponent();
_logger = logger;
_logic = logic;
}
/// <summary>
/// Загрузка писем
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FormMail_Load(object sender, EventArgs e)
{
LoadData();
}
/// <summary>
/// Кнопка переключения на предыдущую страницу
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonPrev_Click(object sender, EventArgs e)
{
if (CurrentPage - 1 <= 0)
{
return;
}
CurrentPage--;
LoadData();
}
/// <summary>
/// Кнопка переключения на следующую страницу
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonNext_Click(object sender, EventArgs e)
{
CurrentPage++;
LoadData();
}
/// <summary>
/// Кнопка "Отправить"
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonReply_Click(object sender, EventArgs e)
{
if (dataGridView.SelectedRows.Count == 1)
{
var service = Program.ServiceProvider?.GetService(typeof(FormMessage));
if (service is FormMessage form)
{
form.MessageId = Convert.ToString(dataGridView.SelectedRows[0].Cells["MessageId"].Value);
if (form.ShowDialog() == DialogResult.OK)
{
LoadData();
}
}
}
}
/// <summary>
/// Метод загрузки писем
/// </summary>
private void LoadData()
{
try
{
var list = _logic.ReadList(new MessageInfoSearchModel
{
PageSize = PageSize,
CurrentPage = CurrentPage
});
if (list != null && list.Count == 0 && CurrentPage != 1)
{
CurrentPage--;
list = _logic.ReadList(new MessageInfoSearchModel
{
PageSize = PageSize,
CurrentPage = CurrentPage
});
}
if (list != null)
{
dataGridView.DataSource = list;
dataGridView.Columns["MessageId"].Visible = false;
dataGridView.Columns["ClientId"].Visible = false;
dataGridView.Columns["Body"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
labelPage.Text = $"Страница {CurrentPage}";
_logger.LogInformation("Загрузка писем");
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка загрузки писем");
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -34,22 +34,22 @@
buttonRefresh = new Button();
menuStrip = new MenuStrip();
справочникиToolStripMenuItem = new ToolStripMenuItem();
магазиныToolStripMenuItem = new ToolStripMenuItem();
компонентыToolStripMenuItem = new ToolStripMenuItem();
изделияToolStripMenuItem = new ToolStripMenuItem();
магазиныToolStripMenuItem = new ToolStripMenuItem();
клиентыToolStripMenuItem = new ToolStripMenuItem();
исполнителиToolStripMenuItem = new ToolStripMenuItem();
отчетыToolStripMenuItem = new ToolStripMenuItem();
изделияToolStripMenuItem1 = new ToolStripMenuItem();
изделияСКомпонентамиToolStripMenuItem = new ToolStripMenuItem();
списокЗаказовToolStripMenuItem = new ToolStripMenuItem();
buttonAddPlaneInShop = new Button();
buttonSellPlanes = new Button();
заказыСГруппировкойToolStripMenuItem = new ToolStripMenuItem();
списокМагазиновToolStripMenuItem = new ToolStripMenuItem();
ассортиментМагазиновToolStripMenuItem = new ToolStripMenuItem();
клиентыToolStripMenuItem = new ToolStripMenuItem();
запускРаботToolStripMenuItem = new ToolStripMenuItem();
исполнителиToolStripMenuItem = new ToolStripMenuItem();
buttonAddPlaneInShop = new Button();
buttonSellPlanes = new Button();
почтаToolStripMenuItem = new ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
menuStrip.SuspendLayout();
SuspendLayout();
@ -104,7 +104,7 @@
//
// menuStrip
//
menuStrip.Items.AddRange(new ToolStripItem[] { справочникиToolStripMenuItem, отчетыToolStripMenuItem, запускРаботToolStripMenuItem });
menuStrip.Items.AddRange(new ToolStripItem[] { справочникиToolStripMenuItem, отчетыToolStripMenuItem, запускРаботToolStripMenuItem, почтаToolStripMenuItem });
menuStrip.Location = new Point(0, 0);
menuStrip.Name = "menuStrip";
menuStrip.Size = new Size(984, 24);
@ -113,41 +113,46 @@
//
// справочникиToolStripMenuItem
//
справочникиToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { компонентыToolStripMenuItem, изделияToolStripMenuItem, магазиныToolStripMenuItem });
справочникиToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { компонентыToolStripMenuItem, изделияToolStripMenuItem, клиентыToolStripMenuItem });
справочникиToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { компонентыToolStripMenuItem, изделияToolStripMenuItem, клиентыToolStripMenuItem, исполнителиToolStripMenuItem });
справочникиToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { магазиныToolStripMenuItem, компонентыToolStripMenuItem, изделияToolStripMenuItem, клиентыToolStripMenuItem, исполнителиToolStripMenuItem });
справочникиToolStripMenuItem.Name = "справочникиToolStripMenuItem";
справочникиToolStripMenuItem.Size = new Size(94, 20);
справочникиToolStripMenuItem.Text = "Справочники";
//
// магазиныToolStripMenuItem
//
магазиныToolStripMenuItem.Name = агазиныToolStripMenuItem";
магазиныToolStripMenuItem.Size = new Size(149, 22);
магазиныToolStripMenuItem.Text = "Магазины";
магазиныToolStripMenuItem.Click += магазиныToolStripMenuItem_Click;
//
// компонентыToolStripMenuItem
//
компонентыToolStripMenuItem.Name = омпонентыToolStripMenuItem";
компонентыToolStripMenuItem.Size = new Size(180, 22);
компонентыToolStripMenuItem.Size = new Size(149, 22);
компонентыToolStripMenuItem.Text = "Компоненты";
компонентыToolStripMenuItem.Click += компонентыToolStripMenuItem_Click;
//
// изделияToolStripMenuItem
//
изделияToolStripMenuItem.Name = "изделияToolStripMenuItem";
изделияToolStripMenuItem.Size = new Size(180, 22);
изделияToolStripMenuItem.Size = new Size(149, 22);
изделияToolStripMenuItem.Text = "Изделия";
изделияToolStripMenuItem.Click += изделияToolStripMenuItem_Click;
//
// магазиныToolStripMenuItem
//
магазиныToolStripMenuItem.Name = агазиныToolStripMenuItem";
магазиныToolStripMenuItem.Size = new Size(145, 22);
магазиныToolStripMenuItem.Text = "Магазины";
магазиныToolStripMenuItem.Click += магазиныToolStripMenuItem_Click;
//
// клиентыToolStripMenuItem
//
клиентыToolStripMenuItem.Name = "клиентыToolStripMenuItem";
клиентыToolStripMenuItem.Size = new Size(180, 22);
клиентыToolStripMenuItem.Size = new Size(149, 22);
клиентыToolStripMenuItem.Text = "Клиенты";
клиентыToolStripMenuItem.Click += клиентыToolStripMenuItem_Click;
//
// исполнителиToolStripMenuItem
//
исполнителиToolStripMenuItem.Name = сполнителиToolStripMenuItem";
исполнителиToolStripMenuItem.Size = new Size(149, 22);
исполнителиToolStripMenuItem.Text = "Исполнители";
исполнителиToolStripMenuItem.Click += исполнителиToolStripMenuItem_Click;
//
// отчетыToolStripMenuItem
//
отчетыToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { изделияToolStripMenuItem1, изделияСКомпонентамиToolStripMenuItem, списокЗаказовToolStripMenuItem, заказыСГруппировкойToolStripMenuItem, списокМагазиновToolStripMenuItem, ассортиментМагазиновToolStripMenuItem });
@ -158,44 +163,24 @@
// изделияToolStripMenuItem1
//
изделияToolStripMenuItem1.Name = "изделияToolStripMenuItem1";
изделияToolStripMenuItem1.Size = new Size(215, 22);
изделияToolStripMenuItem1.Size = new Size(250, 22);
изделияToolStripMenuItem1.Text = "Изделия";
изделияToolStripMenuItem1.Click += изделияToolStripMenuItem1_Click;
//
// изделияСКомпонентамиToolStripMenuItem
//
изделияСКомпонентамиToolStripMenuItem.Name = "изделияСКомпонентамиToolStripMenuItem";
изделияСКомпонентамиToolStripMenuItem.Size = new Size(215, 22);
изделияСКомпонентамиToolStripMenuItem.Size = new Size(250, 22);
изделияСКомпонентамиToolStripMenuItem.Text = "Изделия с компонентами";
изделияСКомпонентамиToolStripMenuItem.Click += изделияСКомпонентамиToolStripMenuItem_Click;
//
// списокЗаказовToolStripMenuItem
//
списокЗаказовToolStripMenuItem.Name = "списокЗаказовToolStripMenuItem";
списокЗаказовToolStripMenuItem.Size = new Size(215, 22);
списокЗаказовToolStripMenuItem.Size = new Size(250, 22);
списокЗаказовToolStripMenuItem.Text = "Список заказов";
списокЗаказовToolStripMenuItem.Click += списокЗаказовToolStripMenuItem_Click;
//
// buttonAddPlaneInShop
//
buttonAddPlaneInShop.Location = new Point(822, 210);
buttonAddPlaneInShop.Name = "buttonAddPlaneInShop";
buttonAddPlaneInShop.Size = new Size(150, 50);
buttonAddPlaneInShop.TabIndex = 7;
buttonAddPlaneInShop.Text = "Добавить изделие\r\nв магазин";
buttonAddPlaneInShop.UseVisualStyleBackColor = true;
buttonAddPlaneInShop.Click += buttonAddPlaneInShop_Click;
//
// buttonSellPlanes
//
buttonSellPlanes.Location = new Point(822, 266);
buttonSellPlanes.Name = "buttonSellPlanes";
buttonSellPlanes.Size = new Size(150, 23);
buttonSellPlanes.TabIndex = 8;
buttonSellPlanes.Text = "Продать изделия";
buttonSellPlanes.UseVisualStyleBackColor = true;
buttonSellPlanes.Click += buttonSellPlanes_Click;
//
// заказыСГруппировкойToolStripMenuItem
//
заказыСГруппировкойToolStripMenuItem.Name = аказыСГруппировкойToolStripMenuItem";
@ -217,7 +202,6 @@
ассортиментМагазиновToolStripMenuItem.Text = "Ассортимент магазинов";
ассортиментМагазиновToolStripMenuItem.Click += ассортиментМагазиновToolStripMenuItem_Click;
//
// клиентыToolStripMenuItem
// запускРаботToolStripMenuItem
//
запускРаботToolStripMenuItem.Name = апускРаботToolStripMenuItem";
@ -225,12 +209,32 @@
запускРаботToolStripMenuItem.Text = "Запуск работ";
запускРаботToolStripMenuItem.Click += запускРаботToolStripMenuItem_Click;
//
// исполнителиToolStripMenuItem
// buttonAddPlaneInShop
//
исполнителиToolStripMenuItem.Name = сполнителиToolStripMenuItem";
исполнителиToolStripMenuItem.Size = new Size(180, 22);
исполнителиToolStripMenuItem.Text = "Исполнители";
исполнителиToolStripMenuItem.Click += исполнителиToolStripMenuItem_Click;
buttonAddPlaneInShop.Location = new Point(822, 210);
buttonAddPlaneInShop.Name = "buttonAddPlaneInShop";
buttonAddPlaneInShop.Size = new Size(150, 50);
buttonAddPlaneInShop.TabIndex = 7;
buttonAddPlaneInShop.Text = "Добавить изделие\r\nв магазин";
buttonAddPlaneInShop.UseVisualStyleBackColor = true;
buttonAddPlaneInShop.Click += buttonAddPlaneInShop_Click;
//
// buttonSellPlanes
//
buttonSellPlanes.Location = new Point(822, 266);
buttonSellPlanes.Name = "buttonSellPlanes";
buttonSellPlanes.Size = new Size(150, 23);
buttonSellPlanes.TabIndex = 8;
buttonSellPlanes.Text = "Продать изделия";
buttonSellPlanes.UseVisualStyleBackColor = true;
buttonSellPlanes.Click += buttonSellPlanes_Click;
//
// почтаToolStripMenuItem
//
почтаToolStripMenuItem.Name = "почтаToolStripMenuItem";
почтаToolStripMenuItem.Size = new Size(53, 20);
почтаToolStripMenuItem.Text = "Почта";
почтаToolStripMenuItem.Click += почтаToolStripMenuItem_Click;
//
// FormMain
//
@ -278,5 +282,6 @@
private ToolStripMenuItem клиентыToolStripMenuItem;
private ToolStripMenuItem запускРаботToolStripMenuItem;
private ToolStripMenuItem исполнителиToolStripMenuItem;
private ToolStripMenuItem почтаToolStripMenuItem;
}
}

View File

@ -232,6 +232,20 @@ namespace AircraftPlantView
MessageBox.Show("Процесс обработки запущен", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// Посмотреть письма
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void почтаToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormMail));
if (service is FormMail form)
{
form.ShowDialog();
}
}
/// <summary>
/// Кнопка "Создать заказ"
/// </summary>

View File

@ -0,0 +1,118 @@
namespace AircraftPlantView
{
partial class FormMessage
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
labelSubject = new Label();
textBoxSubject = new TextBox();
textBoxBody = new TextBox();
labelBody = new Label();
buttonSend = new Button();
buttonCancel = new Button();
SuspendLayout();
//
// labelSubject
//
labelSubject.AutoSize = true;
labelSubject.Location = new Point(12, 15);
labelSubject.Name = "labelSubject";
labelSubject.Size = new Size(68, 15);
labelSubject.TabIndex = 0;
labelSubject.Text = "Заголовок:";
//
// textBoxSubject
//
textBoxSubject.Location = new Point(90, 12);
textBoxSubject.Name = "textBoxSubject";
textBoxSubject.Size = new Size(282, 23);
textBoxSubject.TabIndex = 1;
//
// textBoxBody
//
textBoxBody.Location = new Point(90, 41);
textBoxBody.Name = "textBoxBody";
textBoxBody.Size = new Size(282, 23);
textBoxBody.TabIndex = 2;
//
// labelBody
//
labelBody.AutoSize = true;
labelBody.Location = new Point(12, 44);
labelBody.Name = "labelBody";
labelBody.Size = new Size(39, 15);
labelBody.TabIndex = 3;
labelBody.Text = "Текст:";
//
// buttonSend
//
buttonSend.Location = new Point(216, 76);
buttonSend.Name = "buttonSend";
buttonSend.Size = new Size(75, 23);
buttonSend.TabIndex = 7;
buttonSend.Text = "Отправить";
buttonSend.UseVisualStyleBackColor = true;
buttonSend.Click += buttonSend_Click;
//
// buttonCancel
//
buttonCancel.Location = new Point(297, 76);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(75, 23);
buttonCancel.TabIndex = 6;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// FormMessage
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(384, 111);
Controls.Add(buttonSend);
Controls.Add(buttonCancel);
Controls.Add(labelBody);
Controls.Add(textBoxBody);
Controls.Add(textBoxSubject);
Controls.Add(labelSubject);
Name = "FormMessage";
Text = "Письмо";
Load += FormMessage_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label labelSubject;
private TextBox textBoxSubject;
private TextBox textBoxBody;
private Label labelBody;
private Button buttonSend;
private Button buttonCancel;
}
}

View File

@ -0,0 +1,142 @@
using AircraftPlantBusinessLogic.MailWorker;
using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.ViewModels;
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 AircraftPlantView
{
/// <summary>
/// Форма для отправки письма
/// </summary>
public partial class FormMessage : Form
{
/// <summary>
/// Логгер
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Бизнес-логика для писем
/// </summary>
private readonly IMessageInfoLogic _messageLogic;
/// <summary>
/// Бизнес-логика для отправки писем
/// </summary>
private readonly AbstractMailWorker _mailWorker;
/// <summary>
/// Письмо
/// </summary>
private MessageInfoViewModel? _message;
/// <summary>
/// Идентификатор сообщения
/// </summary>
public string MessageId { get; set; } = string.Empty;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
/// <param name="messageLogic"></param>
/// <param name="mailWorker"></param>
public FormMessage(ILogger<FormMessage> logger, IMessageInfoLogic messageLogic, AbstractMailWorker mailWorker)
{
InitializeComponent();
_logger = logger;
_messageLogic = messageLogic;
_mailWorker = mailWorker;
}
/// <summary>
/// Загрузка данных
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FormMessage_Load(object sender, EventArgs e)
{
try
{
_message = _messageLogic.ReadElement(new MessageInfoSearchModel
{
MessageId = MessageId
});
if (_message != null)
{
textBoxSubject.Text = _message.Subject;
textBoxBody.Text = _message.Reply;
if (!_message.IsChecked)
{
_messageLogic.Update(new MessageInfoBindingModel
{
MessageId = MessageId,
IsChecked = true,
Reply = _message.Reply
});
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения собщения");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Кнопка "Отправить"
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonSend_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxBody.Text))
{
MessageBox.Show("Заполните ответ", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
_mailWorker.MailSendAsync(new()
{
MailAddress = _message!.SenderName,
Subject = _message.Subject,
Text = textBoxBody.Text,
});
_messageLogic.Update(new MessageInfoBindingModel
{
MessageId = MessageId,
IsChecked = true,
Reply = textBoxBody.Text
});
MessageBox.Show("Отправка прошла успешно", "Сообщение", MessageBoxButtons.OK);
DialogResult = DialogResult.OK;
Close();
}
/// <summary>
/// Кнопка "Отмена"
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -8,6 +8,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using System;
using AircraftPlantBusinessLogic.MailWorker;
using AircraftPlantContracts.BindingModels;
namespace AircraftPlantView
{
@ -33,7 +35,30 @@ namespace AircraftPlantView
ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider();
Application.Run(_serviceProvider.GetRequiredService<FormMain>());
// Íàñòðîéêà äëÿ îòïðàâêè ïèñåì
try
{
var mailSender = _serviceProvider.GetService<AbstractMailWorker>();
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, 60000);
}
catch (Exception ex)
{
var logger = _serviceProvider.GetService<ILogger>();
logger?.LogError(ex, "Îøèáêà ðàáîòû ñ ïî÷òîé");
}
Application.Run(_serviceProvider.GetRequiredService<FormMain>());
}
/// <summary>
@ -54,6 +79,7 @@ namespace AircraftPlantView
services.AddTransient<IOrderStorage, OrderStorage>();
services.AddTransient<IPlaneStorage, PlaneStorage>();
services.AddTransient<IShopStorage, ShopStorage>();
services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
services.AddTransient<IClientLogic, ClientLogic>();
services.AddTransient<IImplementerLogic, ImplementerLogic>();
@ -62,7 +88,10 @@ namespace AircraftPlantView
services.AddTransient<IPlaneLogic, PlaneLogic>();
services.AddTransient<IReportLogic, ReportLogic>();
services.AddTransient<IShopLogic, ShopLogic>();
services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
services.AddTransient<IWorkProcess, WorkModeling>();
services.AddSingleton<AbstractMailWorker, MailKitWorker>();
services.AddTransient<AbstractSaveToWord, SaveToWord>();
services.AddTransient<AbstractSaveToExcel, SaveToExcel>();
@ -86,6 +115,14 @@ namespace AircraftPlantView
services.AddTransient<FormReportOrders>();
services.AddTransient<FormReportGroupOrders>();
services.AddTransient<FormReportShopPlanes>();
services.AddTransient<FormMail>();
services.AddTransient<FormMessage>();
}
/// <summary>
/// Ïðîâåðêà ïî÷òû
/// </summary>
/// <param name="obj"></param>
private static void MailCheck(object obj) => ServiceProvider?.GetService<AbstractMailWorker>()?.MailCheck();
}
}