оно почти работает

This commit is contained in:
Вячеслав Иванов 2024-04-03 09:19:16 +04:00
parent 187759c9ee
commit c9b5db7d4b
31 changed files with 1940 additions and 591 deletions

View File

@ -12,79 +12,111 @@ using System.Threading.Tasks;
namespace PizzeriaBusinessLogic.BusinessLogics namespace PizzeriaBusinessLogic.BusinessLogics
{ {
public class MessageInfoLogic : IMessageInfoLogic public class MessageInfoLogic : IMessageInfoLogic
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IMessageInfoStorage _messageInfoStorage; private readonly IMessageInfoStorage _messageInfoStorage;
private readonly IClientStorage _clientStorage; private readonly IClientStorage _clientStorage;
public MessageInfoLogic(ILogger<MessageInfoLogic> logger, IMessageInfoStorage messageInfoStorage, IClientStorage clientStorage) public MessageInfoLogic(ILogger<MessageInfoLogic> logger, IMessageInfoStorage messageInfoStorage, IClientStorage clientStorage)
{ {
_logger = logger; _logger = logger;
_messageInfoStorage = messageInfoStorage; _messageInfoStorage = messageInfoStorage;
_clientStorage = clientStorage; _clientStorage = clientStorage;
} }
public List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model) public List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model)
{ {
_logger.LogInformation("ReadList. MessageId:{MessageId}.ClientId:{ClientId}", model?.MessageId, model?.ClientId); if (model == null)
var list = model == null ? _messageInfoStorage.GetFullList() : _messageInfoStorage.GetFilteredList(model); {
if (list == null) throw new ArgumentNullException(nameof(model));
{ }
_logger.LogWarning("ReadList return null list"); _logger.LogInformation("ReadList. MessageId:{MessageId}.ClientId:{ClientId}.PageLength:{PageLength}.PageCount:{PageIndex}", model?.MessageId, model?.ClientId, model?.PageLength, model?.PageIndex);
return null; var list = _messageInfoStorage.GetFilteredList(model);
} if (list == null)
_logger.LogInformation("ReadList. Count:{Count}", list.Count); {
return list; _logger.LogWarning("ReadList return null list");
} return null;
public bool Create(MessageInfoBindingModel model) }
{ _logger.LogInformation("ReadList. Count:{Count}", list.Count);
CheckModel(model); return list;
if (_messageInfoStorage.Insert(model) == null) }
{ public bool Create(MessageInfoBindingModel model)
_logger.LogWarning("Insert operation failed"); {
return false; CheckModel(model);
} var message = _messageInfoStorage.Insert(model);
return true; if (message == null)
} {
private void CheckModel(MessageInfoBindingModel model, bool withParams = true) _logger.LogWarning("Insert operation failed");
{ return false;
if (model == null) }
{ return true;
throw new ArgumentNullException(nameof(model)); }
} private void CheckModel(MessageInfoBindingModel model, bool withParams = true)
if (!withParams) {
{ if (model == null)
return; {
} throw new ArgumentNullException(nameof(model));
if (string.IsNullOrEmpty(model.MessageId)) }
{ if (string.IsNullOrEmpty(model.MessageId))
throw new ArgumentNullException("Не указан id сообщения", nameof(model.MessageId)); {
} throw new ArgumentNullException("Не указан id сообщения", nameof(model.MessageId));
if (string.IsNullOrEmpty(model.SenderName)) }
{ if (!withParams)
throw new ArgumentNullException("Не указао почта", nameof(model.SenderName)); {
} return;
if (string.IsNullOrEmpty(model.Subject)) }
{ if (string.IsNullOrEmpty(model.SenderName))
throw new ArgumentNullException("Не указана тема", nameof(model.Subject)); {
} throw new ArgumentNullException("Не указао имя отправителя(электронная почта)", nameof(model.SenderName));
if (string.IsNullOrEmpty(model.Body)) }
{ if (string.IsNullOrEmpty(model.Subject))
throw new ArgumentNullException("Не указан текст сообщения", nameof(model.Subject)); {
} throw new ArgumentNullException("Не указана темма", nameof(model.Subject));
}
if (string.IsNullOrEmpty(model.Body))
{
throw new ArgumentNullException("Не указан текст сообщения", nameof(model.Subject));
}
_logger.LogInformation("MessageInfo. MessageId:{MessageId}.SenderName:{SenderName}.Subject:{Subject}.Body:{Body}", model.MessageId, model.SenderName, model.Subject, model.Body);
var element = _clientStorage.GetElement(new ClientSearchModel
{
Email = model.SenderName
});
if (element == null)
{
_logger.LogWarning("Не удалоссь найти клиента, отправившего письмо с адреса Email:{Email}", model.SenderName);
}
else
{
model.ClientId = element.Id;
}
}
_logger.LogInformation("MessageInfo. MessageId:{MessageId}.SenderName:{SenderName}.Subject:{Subject}.Body:{Body}", model.MessageId, model.SenderName, model.Subject, model.Body); public MessageInfoViewModel? ReadElement(MessageInfoSearchModel model)
var element = _clientStorage.GetElement(new ClientSearchModel {
{ if (model == null)
Email = model.SenderName {
}); throw new ArgumentNullException(nameof(model));
if (element == null) }
{ _logger.LogInformation("ReadElement. MessageId:{MessageId}", model?.MessageId);
_logger.LogWarning("Не удалоссь найти клиента, отправившего письмо с адреса Email:{Email}", model.SenderName); var element = _messageInfoStorage.GetElement(model);
} if (element == null)
else {
{ _logger.LogWarning("ReadElement element not found");
model.ClientId = element.Id; return null;
} }
} _logger.LogInformation("ReadElement find. Id:{Id}", element.MessageId);
} return element;
}
public bool Update(MessageInfoBindingModel model)
{
CheckModel(model, withParams: false);
if (_messageInfoStorage.Update(model) == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
return true;
}
}
} }

View File

@ -17,13 +17,12 @@ namespace PizzeriaBusinessLogic.BusinessLogics
private readonly AbstractMailWorker _mailWorker; private readonly AbstractMailWorker _mailWorker;
static readonly object _locker = new object(); static readonly object _locker = new object();
private readonly IShopStorage _shopStorage; private readonly IShopStorage _shopStorage;
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IShopStorage shopStorage, AbstractMailWorker mailWorker)
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IShopStorage shopStorage)
{ {
_logger = logger; _logger = logger;
_orderStorage = orderStorage; _orderStorage = orderStorage;
_mailWorker = mailWorker;
_shopStorage = shopStorage; _shopStorage = shopStorage;
_mailWorker = mailWorker;
} }
public OrderViewModel? ReadElement(OrderSearchModel model) public OrderViewModel? ReadElement(OrderSearchModel model)
@ -96,7 +95,7 @@ namespace PizzeriaBusinessLogic.BusinessLogics
{ {
lock (_locker) lock (_locker)
{ {
model = FillOrderBindingModel(model); (model, var element) = FillOrderBindingModel(model);
if (model.Status != OrderStatus.Готов && model.Status != OrderStatus.Ожидает) if (model.Status != OrderStatus.Готов && model.Status != OrderStatus.Ожидает)
{ {
_logger.LogWarning("Changing status operation faled: Current-{Status}:required-Выдан.", model.Status); _logger.LogWarning("Changing status operation faled: Current-{Status}:required-Выдан.", model.Status);
@ -108,14 +107,16 @@ namespace PizzeriaBusinessLogic.BusinessLogics
Count = model.Count Count = model.Count
})) }))
{ {
if (model.Status == OrderStatus.Готов || model.Status == OrderStatus.Ожидает) if (model.Status == OrderStatus.Готов)
{ {
model.Status = OrderStatus.Ожидает; model.Status = OrderStatus.Ожидает;
return UpdateOrder(model);
UpdateOrder(model, element);
} }
throw new ArgumentException("Недостаточно места в магазинах для поставки");
} }
model.Status = OrderStatus.Выдан; model.Status = OrderStatus.Выдан;
return UpdateOrder(model); return UpdateOrder(model, element);
} }
} }
@ -146,20 +147,20 @@ namespace PizzeriaBusinessLogic.BusinessLogics
} }
private bool ChangeStatus(OrderBindingModel model, OrderStatus requiredStatus) private bool ChangeStatus(OrderBindingModel model, OrderStatus requiredStatus)
{ {
model = FillOrderBindingModel(model); (model, var element) = FillOrderBindingModel(model);
if (requiredStatus - model.Status == 1) if (requiredStatus - model.Status == 1)
{ {
model.Status = requiredStatus; model.Status = requiredStatus;
if (model.Status == OrderStatus.Готов) if (model.Status == OrderStatus.Готов)
model.DateImplement = DateTime.Now; model.DateImplement = DateTime.Now;
return UpdateOrder(model); return UpdateOrder(model, element);
} }
_logger.LogWarning("Changing status operation faled: Current-{Status}:required-{requiredStatus}.", model.Status, requiredStatus); _logger.LogWarning("Changing status operation faled: Current-{Status}:required-{requiredStatus}.", model.Status, requiredStatus);
throw new InvalidOperationException($"Невозможно приствоить статус {requiredStatus} заказу с текущим статусом {model.Status}"); throw new InvalidOperationException($"Невозможно приствоить статус {requiredStatus} заказу с текущим статусом {model.Status}");
} }
private OrderBindingModel FillOrderBindingModel(OrderBindingModel model) private (OrderBindingModel, OrderViewModel) FillOrderBindingModel(OrderBindingModel model)
{ {
CheckModel(model, false); CheckModel(model, false);
var element = _orderStorage.GetElement(new OrderSearchModel() var element = _orderStorage.GetElement(new OrderSearchModel()
@ -175,41 +176,17 @@ namespace PizzeriaBusinessLogic.BusinessLogics
model.PizzaId = element.PizzaId; model.PizzaId = element.PizzaId;
model.DateImplement = element.DateImplement; model.DateImplement = element.DateImplement;
model.ClientId = element.ClientId; model.ClientId = element.ClientId;
model.Status = element.Status;
model.Count = element.Count;
model.Sum = element.Sum;
if (!model.ImplementerId.HasValue) if (!model.ImplementerId.HasValue)
{ {
model.ImplementerId = element.ImplementerId; model.ImplementerId = element.ImplementerId;
} }
model.Status = element.Status; return (model, element);
model.Count = element.Count;
model.Sum = element.Sum;
if (requiredStatus - model.Status == 1)
{
model.Status = requiredStatus;
if (model.Status == OrderStatus.Готов)
{
model.DateImplement = DateTime.Now;
}
if (_orderStorage.Update(model) == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
string DateInfo = model.DateImplement.HasValue ? $"Дата выполнения {model.DateImplement}" : "";
Task.Run(() => _mailWorker.MailSendAsync(new MailSendInfoBindingModel
{
MailAddress = element.ClientEmail,
Subject = $"Изменение статуса заказа номер {element.Id}",
Text = $"Ваш заказ номер {element.Id} на пиццу {element.PizzaName} от {element.DateCreate} на сумму {element.Sum} {model.Status}. {DateInfo}"
}));
return true;
}
_logger.LogWarning("Changing status operation faled: Current-{Status}:required-{requiredStatus}.", model.Status, requiredStatus);
throw new InvalidOperationException($"Невозможно приствоить статус {requiredStatus} заказу с текущим статусом {model.Status}");
}
return model;
} }
private bool UpdateOrder(OrderBindingModel model) private bool UpdateOrder(OrderBindingModel model, OrderViewModel MailNotificationModel)
{ {
if (_orderStorage.Update(model) == null) if (_orderStorage.Update(model) == null)
{ {
@ -217,6 +194,14 @@ namespace PizzeriaBusinessLogic.BusinessLogics
return false; return false;
} }
_logger.LogWarning("Update operation sucsess"); _logger.LogWarning("Update operation sucsess");
string DateInfo = model.DateImplement.HasValue ? $"Дата выполнения {model.DateImplement}" : "";
Task.Run(() => _mailWorker.MailSendAsync(new MailSendInfoBindingModel
{
MailAddress = MailNotificationModel.ClientEmail,
Subject = $"Изменение статуса заказа номер {MailNotificationModel.Id}",
Text = $"Ваш заказ номер {MailNotificationModel.Id} на изделие {MailNotificationModel.PizzaName} от" +
$" {MailNotificationModel.DateCreate} на сумму {MailNotificationModel.Sum} {model.Status}. {DateInfo}"
}));
return true; return true;
} }
} }

View File

@ -9,77 +9,121 @@ using System.Threading.Tasks;
namespace PizzeriaBusinessLogic.MailWorker namespace PizzeriaBusinessLogic.MailWorker
{ {
public abstract class AbstractMailWorker public abstract class AbstractMailWorker
{ {
protected string _mailLogin = string.Empty; protected string _mailLogin = string.Empty;
protected string _mailPassword = string.Empty; protected string _mailPassword = string.Empty;
protected string _smtpClientHost = string.Empty; protected string _smtpClientHost = string.Empty;
protected int _smtpClientPort; protected int _smtpClientPort;
protected string _popHost = string.Empty; protected string _popHost = string.Empty;
protected int _popPort; protected int _popPort;
private readonly IMessageInfoLogic _messageInfoLogic; private readonly IMessageInfoLogic _messageInfoLogic;
private readonly ILogger _logger; private readonly ILogger _logger;
public AbstractMailWorker(ILogger<AbstractMailWorker> logger, IMessageInfoLogic messageInfoLogic) public AbstractMailWorker(ILogger<AbstractMailWorker> logger, IMessageInfoLogic messageInfoLogic)
{ {
_logger = logger; _logger = logger;
_messageInfoLogic = messageInfoLogic; _messageInfoLogic = messageInfoLogic;
} }
public void MailConfig(MailConfigBindingModel config) public void MailConfig(MailConfigBindingModel config)
{ {
_mailLogin = config.MailLogin; _mailLogin = config.MailLogin;
_mailPassword = config.MailPassword; _mailPassword = config.MailPassword;
_smtpClientHost = config.SmtpClientHost; _smtpClientHost = config.SmtpClientHost;
_smtpClientPort = config.SmtpClientPort; _smtpClientPort = config.SmtpClientPort;
_popHost = config.PopHost; _popHost = config.PopHost;
_popPort = config.PopPort; _popPort = config.PopPort;
_logger.LogDebug("Config: {login}, {password}, {clientHost}, {clientPOrt}, {popHost}, {popPort}", _mailLogin, _mailPassword.Length, _smtpClientHost, _smtpClientPort, _popHost, _popPort); _logger.LogDebug("Config: {login}, {password}, {clientHost}, {clientPOrt}, {popHost}, {popPort}", _mailLogin, _mailPassword.Length, _smtpClientHost, _smtpClientPort, _popHost, _popPort);
} }
public async void MailSendAsync(MailSendInfoBindingModel info) public async void MailSendAsync(MailSendInfoBindingModel info)
{ {
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword)) if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{ {
return; return;
} }
if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0) if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0)
{ {
return; return;
} }
if (string.IsNullOrEmpty(info.MailAddress) || string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Text)) if (string.IsNullOrEmpty(info.MailAddress) || string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Text))
{ {
return; return;
} }
_logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject); _logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject);
await SendMailAsync(info); await SendMailAsync(info);
} }
public async void MailCheck() public async void MailCheck()
{ {
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword)) if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{ {
return; return;
} }
if (string.IsNullOrEmpty(_popHost) || _popPort == 0) if (string.IsNullOrEmpty(_popHost) || _popPort == 0)
{ {
return; return;
} }
if (_messageInfoLogic == null) if (_messageInfoLogic == null)
{ {
return; return;
} }
var list = await ReceiveMailAsync(); var list = await ReceiveMailAsync();
_logger.LogDebug("Check Mail: {Count} new mails", list.Count); _logger.LogDebug("Check Mail: {Count} new mails", list.Count);
foreach (var mail in list) foreach (var mail in list)
{ {
_messageInfoLogic.Create(mail); _messageInfoLogic.Create(mail);
} }
} }
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
protected abstract Task<List<MessageInfoBindingModel>> ReceiveMailAsync(); public async void MailSendReplyAsync(MailReplySendInfoBindingModel 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) || string.IsNullOrEmpty(info.ParentMessageId))
{
return;
}
_logger.LogDebug("Send Mail as reply: {To}, {Subject}, {parentId}", info.MailAddress, info.Subject, info.ParentMessageId);
string? messageId = await SendMailAsync(info);
if (string.IsNullOrEmpty(messageId))
{
throw new InvalidOperationException("Непредвиденная ошибка при отправке сообщения в ответ");
}
if (_messageInfoLogic.Create(new MessageInfoBindingModel
{
MessageId = messageId,
DateDelivery = DateTime.Now,
SenderName = _mailLogin,
IsReply = true,
Subject = info.Subject,
Body = info.Text,
}))
{
_messageInfoLogic.Update(new MessageInfoBindingModel()
{
MessageId = info.ParentMessageId,
ReplyMessageId = messageId,
IsReaded = true
});
}
}
protected abstract Task<string?> SendMailAsync(MailSendInfoBindingModel info);
protected abstract Task<List<MessageInfoBindingModel>> ReceiveMailAsync();
}
} }

View File

@ -13,70 +13,92 @@ using System.Threading.Tasks;
namespace PizzeriaBusinessLogic.MailWorker namespace PizzeriaBusinessLogic.MailWorker
{ {
public class MailKitWorker : AbstractMailWorker public class MailKitWorker : AbstractMailWorker
{ {
public MailKitWorker(ILogger<MailKitWorker> logger, IMessageInfoLogic messageInfoLogic) : base(logger, messageInfoLogic) { } public MailKitWorker(ILogger<MailKitWorker> logger, IMessageInfoLogic messageInfoLogic) : base(logger, messageInfoLogic) { }
protected override async Task SendMailAsync(MailSendInfoBindingModel info) protected override async Task<string?> SendMailAsync(MailSendInfoBindingModel info)
{ {
using var objMailMessage = new MailMessage(); string? resount = null;
using var objSmtpClient = new SmtpClient(_smtpClientHost, _smtpClientPort); using var objMailMessage = new MailMessage();
try using var objSmtpClient = new SmtpClient(_smtpClientHost, _smtpClientPort);
{ try
objMailMessage.From = new MailAddress(_mailLogin); {
objMailMessage.To.Add(new MailAddress(info.MailAddress)); ConfigurateSmtpClient(objSmtpClient);
objMailMessage.Subject = info.Subject; CreateMessage(objMailMessage, info);
objMailMessage.Body = info.Text;
objMailMessage.SubjectEncoding = Encoding.UTF8;
objMailMessage.BodyEncoding = Encoding.UTF8;
objSmtpClient.UseDefaultCredentials = false; if (info is MailReplySendInfoBindingModel replyInfo)
objSmtpClient.EnableSsl = true; {
objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; objMailMessage.Headers.Add("In-Reply-To", replyInfo.ParentMessageId);
objSmtpClient.Credentials = new NetworkCredential(_mailLogin, _mailPassword); objMailMessage.Headers.Add("References", replyInfo.ParentMessageId);
await Task.Run(() => objSmtpClient.Send(objMailMessage)); string messageGuid = Guid.NewGuid().ToString();
} objMailMessage.Headers.Add("Message-Id", messageGuid);
catch (Exception) resount = messageGuid;
{ }
throw;
}
}
protected override async Task<List<MessageInfoBindingModel>> ReceiveMailAsync() await Task.Run(() => objSmtpClient.Send(objMailMessage));
{ }
var list = new List<MessageInfoBindingModel>(); catch (Exception)
using var client = new Pop3Client(); {
await Task.Run(() => throw;
{ }
try return resount;
{ }
client.Connect(_popHost, _popPort, SecureSocketOptions.SslOnConnect);
client.Authenticate(_mailLogin, _mailPassword); protected override async Task<List<MessageInfoBindingModel>> ReceiveMailAsync()
for (int i = 0; i < client.Count; i++) {
{ var list = new List<MessageInfoBindingModel>();
var message = client.GetMessage(i); using var client = new Pop3Client();
foreach (var mail in message.From.Mailboxes) await Task.Run(() =>
{ {
list.Add(new MessageInfoBindingModel try
{ {
DateDelivery = message.Date.DateTime, client.Connect(_popHost, _popPort, SecureSocketOptions.SslOnConnect);
MessageId = message.MessageId, client.Authenticate(_mailLogin, _mailPassword);
SenderName = mail.Address, for (int i = 0; i < client.Count; i++)
Subject = message.Subject, {
Body = message.TextBody var message = client.GetMessage(i);
}); foreach (var mail in message.From.Mailboxes)
} {
} list.Add(new MessageInfoBindingModel
} {
catch (MailKit.Security.AuthenticationException) DateDelivery = message.Date.DateTime,
{ } MessageId = message.MessageId,
finally SenderName = mail.Address,
{ Subject = message.Subject,
client.Disconnect(true); Body = message.TextBody
} });
}); }
return list; }
} }
} catch (MailKit.Security.AuthenticationException)
{ }
finally
{
client.Disconnect(true);
}
});
return list;
}
private void CreateMessage(MailMessage objMailMessage, MailSendInfoBindingModel info)
{
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;
}
private void ConfigurateSmtpClient(SmtpClient objSmtpClient)
{
objSmtpClient.UseDefaultCredentials = false;
objSmtpClient.EnableSsl = true;
objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
objSmtpClient.Credentials = new NetworkCredential(_mailLogin, _mailPassword);
}
}
} }

View File

@ -11,6 +11,8 @@ namespace PizzeriaClientApp
public static ClientViewModel? Client { get; set; } = null; public static ClientViewModel? Client { get; set; } = null;
public static int MailPage { get; set; } = 1;
public static void Connect(IConfiguration configuration) public static void Connect(IConfiguration configuration)
{ {
_client.BaseAddress = new Uri(configuration["IPAddress"]); _client.BaseAddress = new Uri(configuration["IPAddress"]);

View File

@ -145,13 +145,15 @@ namespace PizzeriaClientApp.Controllers
} }
[HttpGet] [HttpGet]
public IActionResult Mails() public IActionResult Mails(int page = 1)
{ {
if (APIClient.Client == null) if (APIClient.Client == null)
{ {
return Redirect("~/Home/Enter"); return Redirect("~/Home/Enter");
} }
return View(APIClient.GetRequest<List<MessageInfoViewModel>>($"api/client/getmessages?clientId={APIClient.Client.Id}"));
page = Math.Max(page, 1);
return View(APIClient.GetRequest<List<MessageInfoViewModel>>($"api/client/getmessages?clientId={APIClient.Client.Id}&page={page}"));
} }
} }
} }

View File

@ -1,6 +1,7 @@
@using PizzeriaContracts.ViewModels @using PizzeriaContracts.ViewModels
@model List<MessageInfoViewModel> @model List<MessageInfoViewModel>
@Url.ActionContext.RouteData.Values["page"]
@{ @{
ViewData["Title"] = "Mails"; ViewData["Title"] = "Mails";
@ -51,5 +52,31 @@
} }
</tbody> </tbody>
</table> </table>
<div class="d-flex justify-content-center align-items-center">
@{
int page;
if (Context.Request.Query.TryGetValue("page", out var pageValue) && !string.IsNullOrEmpty(pageValue))
{
page = int.Parse(pageValue);
}
else
{
page = 1;
}
<div class="m-1">
<input type="number" class="form-control" min="1" step="1" asp-action="Mails" name="page" value="@(page)" readonly>
</div>
if (page > 1)
{
<a name="page" class="btn btn-primary" type="button" asp-action="Mails" asp-route-page="@(page-1)">&lt;-</a>
}
else
{
<p class="btn btn-primary my-auto">&lt;-</p>
}
<a name="" id="" class="btn btn-primary" type="button" asp-action="Mails" asp-route-page="@(page+1)">-&gt;</a>
}
</div>
} }
</div> </div>

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PizzeriaContracts.BindingModels
{
public class MailReplySendInfoBindingModel : MailSendInfoBindingModel
{
public string ParentMessageId { get; set; } = string.Empty;
}
}

View File

@ -7,13 +7,16 @@ using System.Threading.Tasks;
namespace PizzeriaContracts.BindingModels namespace PizzeriaContracts.BindingModels
{ {
public class MessageInfoBindingModel : IMessageInfoModel public class MessageInfoBindingModel : IMessageInfoModel
{ {
public string MessageId { get; set; } = string.Empty; public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; } public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty; public string SenderName { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty; public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty; public string Body { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; } public DateTime DateDelivery { get; set; }
} public bool IsReaded { get; set; }
public string? ReplyMessageId { get; set; }
public bool IsReply { get; set; }
}
} }

View File

@ -9,9 +9,11 @@ using System.Threading.Tasks;
namespace PizzeriaContracts.BusinessLogicsContracts namespace PizzeriaContracts.BusinessLogicsContracts
{ {
public interface IMessageInfoLogic public interface IMessageInfoLogic
{ {
List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model); List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model);
bool Create(MessageInfoBindingModel model); MessageInfoViewModel? ReadElement(MessageInfoSearchModel model);
} bool Create(MessageInfoBindingModel model);
bool Update(MessageInfoBindingModel model);
}
} }

View File

@ -6,9 +6,11 @@ using System.Threading.Tasks;
namespace PizzeriaContracts.SearchModels namespace PizzeriaContracts.SearchModels
{ {
public class MessageInfoSearchModel public class MessageInfoSearchModel
{ {
public int? ClientId { get; set; } public int? ClientId { get; set; }
public string? MessageId { get; set; } public string? MessageId { get; set; }
} public int? PageLength { get; set; }
public int? PageIndex { get; set; }
}
} }

View File

@ -9,11 +9,12 @@ using System.Threading.Tasks;
namespace PizzeriaContracts.StoragesContracts namespace PizzeriaContracts.StoragesContracts
{ {
public interface IMessageInfoStorage public interface IMessageInfoStorage
{ {
List<MessageInfoViewModel> GetFullList(); List<MessageInfoViewModel> GetFullList();
List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model); List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model);
MessageInfoViewModel? GetElement(MessageInfoSearchModel model); MessageInfoViewModel? GetElement(MessageInfoSearchModel model);
MessageInfoViewModel? Insert(MessageInfoBindingModel model); MessageInfoViewModel? Insert(MessageInfoBindingModel model);
} MessageInfoViewModel? Update(MessageInfoBindingModel model);
}
} }

View File

@ -8,22 +8,31 @@ using System.Threading.Tasks;
namespace PizzeriaContracts.ViewModels namespace PizzeriaContracts.ViewModels
{ {
public class MessageInfoViewModel : IMessageInfoModel public class MessageInfoViewModel : IMessageInfoModel
{ {
public string MessageId { get; set; } = string.Empty; public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; } public int? ClientId { get; set; }
[DisplayName("Отправитель")] [DisplayName("Отправитель")]
public string SenderName { get; set; } = string.Empty; public string SenderName { get; set; } = string.Empty;
[DisplayName("Дата письма")] [DisplayName("Дата письма")]
public DateTime DateDelivery { get; set; } public DateTime DateDelivery { get; set; }
[DisplayName("Заголовок")] [DisplayName("Заголовок")]
public string Subject { get; set; } = string.Empty; public string Subject { get; set; } = string.Empty;
[DisplayName("Текст")] [DisplayName("Текст")]
public string Body { get; set; } = string.Empty; public string Body { get; set; } = string.Empty;
}
[DisplayName("Прочитанно")]
public bool IsReaded { get; set; }
public string? ReplyMessageId { get; set; }
public IMessageInfoModel? Reply { get; set; }
public bool IsReply { get; set; }
}
} }

View File

@ -6,13 +6,16 @@ using System.Threading.Tasks;
namespace PizzeriaDataModels.Models namespace PizzeriaDataModels.Models
{ {
public interface IMessageInfoModel public interface IMessageInfoModel
{ {
string MessageId { get; } string MessageId { get; }
int? ClientId { get; } int? ClientId { get; }
string SenderName { get; } string SenderName { get; }
DateTime DateDelivery { get; } DateTime DateDelivery { get; }
string Subject { get; } string Subject { get; }
string Body { get; } string Body { get; }
} bool IsReaded { get; }
string? ReplyMessageId { get; }
bool IsReply { get; }
}
} }

View File

@ -11,42 +11,72 @@ using System.Threading.Tasks;
namespace PizzeriaDatabaseImplement.Implements namespace PizzeriaDatabaseImplement.Implements
{ {
public class MessageInfoStorage : IMessageInfoStorage public class MessageInfoStorage : IMessageInfoStorage
{ {
public List<MessageInfoViewModel> GetFullList() public List<MessageInfoViewModel> GetFullList()
{ {
using var context = new PizzeriaDatabase(); using var context = new PizzeriaDatabase();
return context.MessageInfos.Select(x => x.GetViewModel).ToList(); return context.MessageInfos.Select(x => x.GetViewModel).ToList();
} }
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model) public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{ {
if (!model.ClientId.HasValue) if (!model.ClientId.HasValue && !model.PageLength.HasValue && !model.PageIndex.HasValue)
{ {
return new(); return new();
} }
using var context = new PizzeriaDatabase(); using var context = new PizzeriaDatabase();
return context.MessageInfos.Where(x => x.ClientId.HasValue && x.ClientId == model.ClientId).Select(x => x.GetViewModel).ToList(); IEnumerable<MessageInfo> request = context.MessageInfos.Where(x => !x.IsReply);
} if (model.ClientId.HasValue)
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model) request = request.Where(x => x.ClientId.HasValue && x.ClientId == model.ClientId);
{ if (model.PageLength.HasValue)
if (string.IsNullOrEmpty(model.MessageId)) {
{ int skipRows = model.PageIndex.HasValue ? (model.PageIndex.Value - 1) * model.PageLength.Value : 0;
return new(); request = request.Skip(skipRows).Take(model.PageLength.Value);
} }
using var context = new PizzeriaDatabase();
return context.MessageInfos.FirstOrDefault(x => x.MessageId == model.MessageId)?.GetViewModel; return request.Select(x => x.GetViewModel).ToList();
} }
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{ public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
var newMessage = MessageInfo.Create(model); {
if (newMessage == null) if (string.IsNullOrEmpty(model.MessageId))
{ {
return null; return new();
} }
using var context = new PizzeriaDatabase(); using var context = new PizzeriaDatabase();
context.MessageInfos.Add(newMessage); return context.MessageInfos.FirstOrDefault(x => x.MessageId == model.MessageId)?.GetViewModel;
context.SaveChanges(); }
return newMessage.GetViewModel; public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
} {
} var newMessage = MessageInfo.Create(model);
if (newMessage == null)
{
return null;
}
using var context = new PizzeriaDatabase();
try
{
context.MessageInfos.Add(newMessage);
context.SaveChanges();
return newMessage.GetViewModel;
}
catch (Exception ex)
{
return null;
}
}
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
using var context = new PizzeriaDatabase();
var message = context.MessageInfos.FirstOrDefault(x => x.MessageId == model.MessageId);
if (message == null)
{
return null;
}
message.Update(context, model);
context.SaveChanges();
return message.GetViewModel;
}
}
} }

View File

@ -0,0 +1,392 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PizzeriaDatabaseImplement;
#nullable disable
namespace PizzeriaDatabaseImplement.Migrations
{
[DbContext(typeof(PizzeriaDatabase))]
[Migration("20240402204158_Update")]
partial class Update
{
/// <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("PizzeriaDatabaseImplement.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("PizzeriaDatabaseImplement.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("PizzeriaDatabaseImplement.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("PizzeriaDatabaseImplement.Models.MessageInfo", 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>("IsReaded")
.HasColumnType("bit");
b.Property<bool>("IsReply")
.HasColumnType("bit");
b.Property<string>("ReplyMessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("SenderName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Subject")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.HasIndex("ReplyMessageId");
b.ToTable("MessageInfos");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.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>("PizzaId")
.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("PizzaId");
b.ToTable("Orders");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Pizza", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("PizzaName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Pizzas");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.PizzaComponent", 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>("PizzaId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ComponentId");
b.HasIndex("PizzaId");
b.ToTable("PizzaComponents");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Adress")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("OpeningDate")
.HasColumnType("datetime2");
b.Property<int>("PizzaMaxCount")
.HasColumnType("int");
b.Property<string>("ShopName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.ShopPizzas", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("PizzaId")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PizzaId");
b.HasIndex("ShopId");
b.ToTable("ShopPizzas");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("PizzeriaDatabaseImplement.Models.Client", "Client")
.WithMany("ClientMessages")
.HasForeignKey("ClientId");
b.HasOne("PizzeriaDatabaseImplement.Models.MessageInfo", "Reply")
.WithMany()
.HasForeignKey("ReplyMessageId");
b.Navigation("Client");
b.Navigation("Reply");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Order", b =>
{
b.HasOne("PizzeriaDatabaseImplement.Models.Client", "Client")
.WithMany("ClientOrders")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PizzeriaDatabaseImplement.Models.Implementer", "Implementer")
.WithMany("Order")
.HasForeignKey("ImplementerId");
b.HasOne("PizzeriaDatabaseImplement.Models.Pizza", "Pizza")
.WithMany("Orders")
.HasForeignKey("PizzaId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Client");
b.Navigation("Implementer");
b.Navigation("Pizza");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.PizzaComponent", b =>
{
b.HasOne("PizzeriaDatabaseImplement.Models.Component", "Component")
.WithMany("PizzaComponents")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PizzeriaDatabaseImplement.Models.Pizza", "Pizza")
.WithMany("Components")
.HasForeignKey("PizzaId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Pizza");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.ShopPizzas", b =>
{
b.HasOne("PizzeriaDatabaseImplement.Models.Pizza", "Pizza")
.WithMany()
.HasForeignKey("PizzaId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PizzeriaDatabaseImplement.Models.Shop", "Shop")
.WithMany("Pizzas")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Pizza");
b.Navigation("Shop");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Client", b =>
{
b.Navigation("ClientMessages");
b.Navigation("ClientOrders");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Component", b =>
{
b.Navigation("PizzaComponents");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Implementer", b =>
{
b.Navigation("Order");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Pizza", b =>
{
b.Navigation("Components");
b.Navigation("Orders");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Pizzas");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,70 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PizzeriaDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class Update : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsReaded",
table: "MessageInfos",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "IsReply",
table: "MessageInfos",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "ReplyMessageId",
table: "MessageInfos",
type: "nvarchar(450)",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_MessageInfos_ReplyMessageId",
table: "MessageInfos",
column: "ReplyMessageId");
migrationBuilder.AddForeignKey(
name: "FK_MessageInfos_MessageInfos_ReplyMessageId",
table: "MessageInfos",
column: "ReplyMessageId",
principalTable: "MessageInfos",
principalColumn: "MessageId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_MessageInfos_MessageInfos_ReplyMessageId",
table: "MessageInfos");
migrationBuilder.DropIndex(
name: "IX_MessageInfos_ReplyMessageId",
table: "MessageInfos");
migrationBuilder.DropColumn(
name: "IsReaded",
table: "MessageInfos");
migrationBuilder.DropColumn(
name: "IsReply",
table: "MessageInfos");
migrationBuilder.DropColumn(
name: "ReplyMessageId",
table: "MessageInfos");
}
}
}

View File

@ -109,6 +109,15 @@ namespace PizzeriaDatabaseImplement.Migrations
b.Property<DateTime>("DateDelivery") b.Property<DateTime>("DateDelivery")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
b.Property<bool>("IsReaded")
.HasColumnType("bit");
b.Property<bool>("IsReply")
.HasColumnType("bit");
b.Property<string>("ReplyMessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("SenderName") b.Property<string>("SenderName")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -121,6 +130,8 @@ namespace PizzeriaDatabaseImplement.Migrations
b.HasIndex("ClientId"); b.HasIndex("ClientId");
b.HasIndex("ReplyMessageId");
b.ToTable("MessageInfos"); b.ToTable("MessageInfos");
}); });
@ -213,15 +224,6 @@ namespace PizzeriaDatabaseImplement.Migrations
b.ToTable("PizzaComponents"); b.ToTable("PizzaComponents");
}); });
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("PizzeriaDatabaseImplement.Models.Client", "Client")
.WithMany("ClientMessages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Shop", b => modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Shop", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -275,6 +277,21 @@ namespace PizzeriaDatabaseImplement.Migrations
b.ToTable("ShopPizzas"); b.ToTable("ShopPizzas");
}); });
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("PizzeriaDatabaseImplement.Models.Client", "Client")
.WithMany("ClientMessages")
.HasForeignKey("ClientId");
b.HasOne("PizzeriaDatabaseImplement.Models.MessageInfo", "Reply")
.WithMany()
.HasForeignKey("ReplyMessageId");
b.Navigation("Client");
b.Navigation("Reply");
});
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Order", b => modelBuilder.Entity("PizzeriaDatabaseImplement.Models.Order", b =>
{ {
b.HasOne("PizzeriaDatabaseImplement.Models.Client", "Client") b.HasOne("PizzeriaDatabaseImplement.Models.Client", "Client")
@ -322,7 +339,7 @@ namespace PizzeriaDatabaseImplement.Migrations
modelBuilder.Entity("PizzeriaDatabaseImplement.Models.ShopPizzas", b => modelBuilder.Entity("PizzeriaDatabaseImplement.Models.ShopPizzas", b =>
{ {
b.HasOne("PizzeriaDatabaseImplement.Models.Pizza", "Pizza") b.HasOne("PizzeriaDatabaseImplement.Models.Pizza", "Pizza")
.WithMany("ShopPizzas") .WithMany()
.HasForeignKey("PizzaId") .HasForeignKey("PizzaId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();

View File

@ -11,54 +11,85 @@ using System.Threading.Tasks;
namespace PizzeriaDatabaseImplement.Models namespace PizzeriaDatabaseImplement.Models
{ {
public class MessageInfo : IMessageInfoModel public class MessageInfo : IMessageInfoModel
{ {
[Key] [Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] [DatabaseGenerated(DatabaseGeneratedOption.None)]
public string MessageId { get; set; } = string.Empty; public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; } public int? ClientId { get; set; }
public virtual Client? Client { get; set; } public virtual Client? Client { get; set; }
[Required] [Required]
public string SenderName { get; set; } = string.Empty; public string SenderName { get; set; } = string.Empty;
[Required] [Required]
public DateTime DateDelivery { get; set; } public DateTime DateDelivery { get; set; }
[Required] [Required]
public string Subject { get; set; } = string.Empty; public string Subject { get; set; } = string.Empty;
[Required] [Required]
public string Body { get; set; } = string.Empty; public string Body { get; set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel? model) [Required]
{ public bool IsReaded { get; set; }
if (model == null)
{
return null;
}
return new()
{
MessageId = model.MessageId,
ClientId = model.ClientId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
Subject = model.Subject,
Body = model.Body,
}; public string? ReplyMessageId { get; set; }
}
public MessageInfoViewModel GetViewModel => new() [ForeignKey("ReplyMessageId")]
{ public virtual MessageInfo? Reply { get; set; }
MessageId = MessageId,
ClientId = ClientId, [Required]
SenderName = SenderName, public bool IsReply { get; set; }
DateDelivery = DateDelivery,
Subject = Subject, public static MessageInfo? Create(MessageInfoBindingModel? model)
Body = Body {
}; 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,
IsReaded = model.IsReaded,
ReplyMessageId = model.ReplyMessageId,
IsReply = model.IsReply
};
}
public void Update(PizzeriaDatabase context, MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
IsReaded = model.IsReaded;
ReplyMessageId = model.ReplyMessageId;
if (!string.IsNullOrEmpty(ReplyMessageId))
{
Reply = context.MessageInfos.First(x => x.MessageId == ReplyMessageId);
}
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
IsReaded = IsReaded,
ReplyMessageId = ReplyMessageId,
Reply = Reply,
IsReply = IsReply
};
}
} }

View File

@ -11,48 +11,61 @@ using System.Threading.Tasks;
namespace PizzeriaFileImplement.Implements namespace PizzeriaFileImplement.Implements
{ {
public class MessageInfoStorage : IMessageInfoStorage public class MessageInfoStorage : IMessageInfoStorage
{ {
private readonly DataFileSingleton _source; private readonly DataFileSingleton _source;
public MessageInfoStorage() public MessageInfoStorage()
{ {
_source = DataFileSingleton.GetInstance(); _source = DataFileSingleton.GetInstance();
} }
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model) public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{ {
if (model.MessageId != null) if (model.MessageId != null)
{ {
return _source.Messages.FirstOrDefault(x => x.MessageId == model.MessageId)?.GetViewModel; return _source.Messages.FirstOrDefault(x => x.MessageId == model.MessageId)?.GetViewModel;
} }
return null; return null;
} }
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model) public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{ {
return _source.Messages var res = _source.Messages.Where(x => !model.ClientId.HasValue || x.ClientId == model.ClientId).Select(x => x.GetViewModel);
.Where(x => x.ClientId == model.ClientId) if (!(model.PageIndex.HasValue && model.PageLength.HasValue))
.Select(x => x.GetViewModel) {
.ToList(); return res.ToList();
} }
return res.Skip((model.PageIndex.Value - 1) * model.PageLength.Value).Take(model.PageLength.Value).ToList();
}
public List<MessageInfoViewModel> GetFullList() public List<MessageInfoViewModel> GetFullList()
{ {
return _source.Messages return _source.Messages
.Select(x => x.GetViewModel) .Select(x => x.GetViewModel)
.ToList(); .ToList();
} }
public MessageInfoViewModel? Insert(MessageInfoBindingModel model) public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{ {
var newMessage = MessageInfo.Create(model); var newMessage = MessageInfo.Create(model);
if (newMessage == null) if (newMessage == null)
{ {
return null; return null;
} }
_source.Messages.Add(newMessage); _source.Messages.Add(newMessage);
_source.SaveMessages(); _source.SaveMessages();
return newMessage.GetViewModel; return newMessage.GetViewModel;
} }
}
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
var res = _source.Messages.FirstOrDefault(x => x.MessageId.Equals(model.MessageId));
if (res != null)
{
res.Update(model);
_source.SaveMessages();
}
return res?.GetViewModel;
}
}
} }

View File

@ -10,71 +10,96 @@ using System.Xml.Linq;
namespace PizzeriaFileImplement.Models namespace PizzeriaFileImplement.Models
{ {
public class MessageInfo : IMessageInfoModel public class MessageInfo : IMessageInfoModel
{ {
public string MessageId { get; private set; } = string.Empty; public string MessageId { get; private set; } = string.Empty;
public int? ClientId { get; private set; } public int? ClientId { get; private set; }
public string SenderName { get; private set; } = string.Empty; public string SenderName { get; private set; } = string.Empty;
public DateTime DateDelivery { get; private set; } = DateTime.Now; public DateTime DateDelivery { get; private set; } = DateTime.Now;
public string Subject { get; private set; } = string.Empty; public string Subject { get; private set; } = string.Empty;
public string Body { get; private set; } = string.Empty; public string Body { get; private set; } = string.Empty;
public bool IsReaded { get; private set; }
public bool IsReply { get; private set; }
public string? ReplyMessageId { get; private set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel model) public static MessageInfo? Create(MessageInfoBindingModel model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new() return new()
{ {
Body = model.Body, Body = model.Body,
Subject = model.Subject, IsReply = model.IsReply,
ClientId = model.ClientId, IsReaded = model.IsReaded,
MessageId = model.MessageId, Subject = model.Subject,
SenderName = model.SenderName, ClientId = model.ClientId,
DateDelivery = model.DateDelivery, MessageId = model.MessageId,
}; SenderName = model.SenderName,
} DateDelivery = model.DateDelivery,
ReplyMessageId = model.ReplyMessageId,
};
}
public static MessageInfo? Create(XElement element) public static MessageInfo? Create(XElement element)
{ {
if (element == null) if (element == null)
{ {
return null; return null;
} }
return new() return new()
{ {
Body = element.Attribute("Body")!.Value, Body = element.Attribute("Body")!.Value,
Subject = element.Attribute("Subject")!.Value, IsReply = Convert.ToBoolean(element.Attribute("IsReply")!.Value),
ClientId = Convert.ToInt32(element.Attribute("ClientId")!.Value), IsReaded = Convert.ToBoolean(element.Attribute("HasRead")!.Value),
MessageId = element.Attribute("MessageId")!.Value, Subject = element.Attribute("Subject")!.Value,
SenderName = element.Attribute("SenderName")!.Value, ClientId = Convert.ToInt32(element.Attribute("ClientId")!.Value),
DateDelivery = Convert.ToDateTime(element.Attribute("DateDelivery")!.Value), MessageId = element.Attribute("MessageId")!.Value,
}; ReplyMessageId = element.Attribute("ReplyMessageId")!.Value,
} SenderName = element.Attribute("SenderName")!.Value,
DateDelivery = Convert.ToDateTime(element.Attribute("DateDelivery")!.Value),
};
}
public MessageInfoViewModel GetViewModel => new() public void Update(MessageInfoBindingModel model)
{ {
Body = Body, if (model == null)
Subject = Subject, {
ClientId = ClientId, return;
MessageId = MessageId, }
SenderName = SenderName, IsReply = model.IsReply;
DateDelivery = DateDelivery, IsReaded = model.IsReaded;
}; }
public XElement GetXElement => new("MessageInfo", public MessageInfoViewModel GetViewModel => new()
new XAttribute("Body", Body), {
new XAttribute("Subject", Subject), Body = Body,
new XAttribute("ClientId", ClientId), IsReply = IsReply,
new XAttribute("MessageId", MessageId), IsReaded = IsReaded,
new XAttribute("SenderName", SenderName), Subject = Subject,
new XAttribute("DateDelivery", DateDelivery) ClientId = ClientId,
); MessageId = MessageId,
} SenderName = SenderName,
DateDelivery = DateDelivery,
ReplyMessageId = ReplyMessageId,
};
public XElement GetXElement => new("MessageInfo",
new XAttribute("Body", Body),
new XAttribute("IsReply", IsReply),
new XAttribute("IsReaded", IsReaded),
new XAttribute("Subject", Subject),
new XAttribute("ClientId", ClientId),
new XAttribute("MessageId", MessageId),
new XAttribute("ReplyMessageId", ReplyMessageId),
new XAttribute("SenderName", SenderName),
new XAttribute("DateDelivery", DateDelivery)
);
}
} }

View File

@ -11,58 +11,83 @@ using System.Threading.Tasks;
namespace PizzeriaListImplement.Implements namespace PizzeriaListImplement.Implements
{ {
public class MessageInfoStorage : IMessageInfoStorage public class MessageInfoStorage : IMessageInfoStorage
{ {
private readonly DataListSingleton _source; private readonly DataListSingleton _source;
public MessageInfoStorage() public MessageInfoStorage()
{ {
_source = DataListSingleton.GetInstance(); _source = DataListSingleton.GetInstance();
} }
public List<MessageInfoViewModel> GetFullList() public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{ {
List<MessageInfoViewModel> result = new(); foreach (var message in _source.Messages)
foreach (var item in _source.Messages) {
{ if (model.MessageId != null && model.MessageId.Equals(message.MessageId))
result.Add(item.GetViewModel); return message.GetViewModel;
} }
return result; return null;
} }
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model) public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{ {
List<MessageInfoViewModel> result = new(); List<MessageInfoViewModel> result = new();
foreach (var item in _source.Messages) foreach (var item in _source.Messages)
{ {
if (item.ClientId.HasValue && item.ClientId == model.ClientId) if (item.ClientId.HasValue && item.ClientId == model.ClientId)
{ {
result.Add(item.GetViewModel); result.Add(item.GetViewModel);
} }
} }
return result;
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model) if (!(model.PageIndex.HasValue && model.PageLength.HasValue))
{ {
foreach (var message in _source.Messages) return result;
{ }
if (model.MessageId != null && model.MessageId.Equals(message.MessageId)) if (model.PageIndex * model.PageLength >= result.Count)
{ {
return message.GetViewModel; return null;
} }
} List<MessageInfoViewModel> filteredResult = new();
return null; for (var i = (model.PageIndex.Value - 1) * model.PageLength.Value; i < model.PageIndex.Value * model.PageLength.Value; i++)
} {
filteredResult.Add(result[i]);
}
return filteredResult;
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model) public List<MessageInfoViewModel> GetFullList()
{ {
var newMessage = MessageInfo.Create(model); List<MessageInfoViewModel> result = new();
if (newMessage == null) foreach (var item in _source.Messages)
{ {
return null; result.Add(item.GetViewModel);
} }
_source.Messages.Add(newMessage); return result;
return newMessage.GetViewModel; }
}
} public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
var newMessage = MessageInfo.Create(model);
if (newMessage == null)
{
return null;
}
_source.Messages.Add(newMessage);
return newMessage.GetViewModel;
}
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
foreach (var message in _source.Messages)
{
if (message.MessageId.Equals(model.MessageId))
{
message.Update(model);
return message.GetViewModel;
}
}
return null;
}
}
} }

View File

@ -9,45 +9,64 @@ using System.Threading.Tasks;
namespace PizzeriaListImplement.Models namespace PizzeriaListImplement.Models
{ {
public class MessageInfo : IMessageInfoModel public class MessageInfo : IMessageInfoModel
{ {
public string MessageId { get; private set; } = string.Empty; public string MessageId { get; private set; } = string.Empty;
public int? ClientId { get; private set; } public int? ClientId { get; private set; }
public string SenderName { get; private set; } = string.Empty; public string SenderName { get; private set; } = string.Empty;
public DateTime DateDelivery { get; private set; } = DateTime.Now; public DateTime DateDelivery { get; private set; } = DateTime.Now;
public string Subject { get; private set; } = string.Empty; public string Subject { get; private set; } = string.Empty;
public string Body { get; private set; } = string.Empty; public string Body { get; private set; } = string.Empty;
public bool IsReaded { get; private set; }
public bool IsReply { get; private set; }
public string? ReplyMessageId { get; private set; }
public static MessageInfo? Create(MessageInfoBindingModel model) public static MessageInfo? Create(MessageInfoBindingModel model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new() return new()
{ {
Body = model.Body, Body = model.Body,
Subject = model.Subject, IsReply = model.IsReply,
ClientId = model.ClientId, IsReaded = model.IsReaded,
MessageId = model.MessageId, Subject = model.Subject,
SenderName = model.SenderName, ClientId = model.ClientId,
DateDelivery = model.DateDelivery, MessageId = model.MessageId,
}; SenderName = model.SenderName,
} DateDelivery = model.DateDelivery,
ReplyMessageId = model.ReplyMessageId,
};
}
public MessageInfoViewModel GetViewModel => new() public void Update(MessageInfoBindingModel model)
{ {
Body = Body, if (model == null)
Subject = Subject, {
ClientId = ClientId, return;
MessageId = MessageId, }
SenderName = SenderName, IsReply = model.IsReply;
DateDelivery = DateDelivery, IsReaded = model.IsReaded;
}; }
}
public MessageInfoViewModel GetViewModel => new()
{
Body = Body,
IsReply = IsReply,
IsReaded = IsReaded,
Subject = Subject,
ClientId = ClientId,
MessageId = MessageId,
SenderName = SenderName,
DateDelivery = DateDelivery,
ReplyMessageId = ReplyMessageId,
};
}
} }

View File

@ -70,21 +70,23 @@ namespace PizzeriaRestApi.Controllers
} }
} }
[HttpGet] [HttpGet]
public List<MessageInfoViewModel>? GetMessages(int clientId) public List<MessageInfoViewModel>? GetMessages(int clientId, int page, int pagesize = 1)
{ {
try try
{ {
return _mailLogic.ReadList(new MessageInfoSearchModel return _mailLogic.ReadList(new MessageInfoSearchModel
{ {
ClientId = clientId ClientId = clientId,
}); PageLength = pagesize,
} PageIndex = page
catch (Exception ex) });
{ }
_logger.LogError(ex, "Ошибка получения писем клиента"); catch (Exception ex)
throw; {
} _logger.LogError(ex, "Ошибка получения писем клиента");
} throw;
} }
}
}
} }

View File

@ -6,13 +6,11 @@
} }
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"SmtpClientHost": "smtp.gmail.com", "SmtpClientHost": "smtp.gmail.com",
"SmtpClientPort": "587", "SmtpClientPort": "587",
"PopHost": "pop.gmail.com", "PopHost": "pop.gmail.com",
"PopPort": "995", "PopPort": "995",
"MailLogin": "laba46466@gmail.com", "MailLogin": "laba46466@gmail.com",
"MailPassword": "iyin rgai wjdh ocmi" "MailPassword": "iyin rgai wjdh ocmi",
"AllowedHosts": "*",
"ShopAPIPassword": "123456" "ShopAPIPassword": "123456"
} }

View File

@ -0,0 +1,182 @@
namespace PizzeriaView
{
partial class FormLetter
{
/// <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()
{
this.textBoxEmail = new System.Windows.Forms.TextBox();
this.labelAdress = new System.Windows.Forms.Label();
this.labelSubject = new System.Windows.Forms.Label();
this.textBoxSubject = new System.Windows.Forms.TextBox();
this.labelBody = new System.Windows.Forms.Label();
this.textBoxBody = new System.Windows.Forms.TextBox();
this.buttonClose = new System.Windows.Forms.Button();
this.buttonReply = new System.Windows.Forms.Button();
this.labelDate = new System.Windows.Forms.Label();
this.textBoxDate = new System.Windows.Forms.TextBox();
this.buttonSend = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBoxEmail
//
this.textBoxEmail.Location = new System.Drawing.Point(72, 6);
this.textBoxEmail.Name = "textBoxEmail";
this.textBoxEmail.ReadOnly = true;
this.textBoxEmail.Size = new System.Drawing.Size(186, 27);
this.textBoxEmail.TabIndex = 0;
//
// labelAdress
//
this.labelAdress.AutoSize = true;
this.labelAdress.Location = new System.Drawing.Point(12, 9);
this.labelAdress.Name = "labelAdress";
this.labelAdress.Size = new System.Drawing.Size(54, 20);
this.labelAdress.TabIndex = 1;
this.labelAdress.Text = "Адрес:";
//
// labelSubject
//
this.labelSubject.AutoSize = true;
this.labelSubject.Location = new System.Drawing.Point(12, 55);
this.labelSubject.Name = "labelSubject";
this.labelSubject.Size = new System.Drawing.Size(47, 20);
this.labelSubject.TabIndex = 2;
this.labelSubject.Text = "Тема:";
//
// textBoxSubject
//
this.textBoxSubject.Location = new System.Drawing.Point(72, 52);
this.textBoxSubject.Name = "textBoxSubject";
this.textBoxSubject.ReadOnly = true;
this.textBoxSubject.Size = new System.Drawing.Size(552, 27);
this.textBoxSubject.TabIndex = 3;
//
// labelBody
//
this.labelBody.AutoSize = true;
this.labelBody.Location = new System.Drawing.Point(12, 96);
this.labelBody.Name = "labelBody";
this.labelBody.Size = new System.Drawing.Size(104, 20);
this.labelBody.TabIndex = 4;
this.labelBody.Text = "Текст письма:";
//
// textBoxBody
//
this.textBoxBody.Location = new System.Drawing.Point(12, 119);
this.textBoxBody.Multiline = true;
this.textBoxBody.Name = "textBoxBody";
this.textBoxBody.ReadOnly = true;
this.textBoxBody.Size = new System.Drawing.Size(612, 186);
this.textBoxBody.TabIndex = 5;
//
// buttonClose
//
this.buttonClose.Location = new System.Drawing.Point(491, 326);
this.buttonClose.Name = "buttonClose";
this.buttonClose.Size = new System.Drawing.Size(111, 39);
this.buttonClose.TabIndex = 6;
this.buttonClose.Text = "Закрыть";
this.buttonClose.UseVisualStyleBackColor = true;
this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click);
//
// buttonReply
//
this.buttonReply.Location = new System.Drawing.Point(290, 326);
this.buttonReply.Name = "buttonReply";
this.buttonReply.Size = new System.Drawing.Size(177, 39);
this.buttonReply.TabIndex = 7;
this.buttonReply.Text = "Ответить";
this.buttonReply.UseVisualStyleBackColor = true;
this.buttonReply.Click += new System.EventHandler(this.buttonReply_Click);
//
// labelDate
//
this.labelDate.AutoSize = true;
this.labelDate.Location = new System.Drawing.Point(278, 9);
this.labelDate.Name = "labelDate";
this.labelDate.Size = new System.Drawing.Size(127, 20);
this.labelDate.TabIndex = 8;
this.labelDate.Text = "Дата получения: ";
//
// textBoxDate
//
this.textBoxDate.Location = new System.Drawing.Point(411, 6);
this.textBoxDate.Name = "textBoxDate";
this.textBoxDate.ReadOnly = true;
this.textBoxDate.Size = new System.Drawing.Size(213, 27);
this.textBoxDate.TabIndex = 9;
//
// buttonSend
//
this.buttonSend.Location = new System.Drawing.Point(149, 326);
this.buttonSend.Name = "buttonSend";
this.buttonSend.Size = new System.Drawing.Size(109, 39);
this.buttonSend.TabIndex = 10;
this.buttonSend.Text = "Отправить";
this.buttonSend.UseVisualStyleBackColor = true;
this.buttonSend.Visible = false;
this.buttonSend.Click += new System.EventHandler(this.buttonSend_Click);
//
// FormLetter
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(636, 377);
this.Controls.Add(this.buttonSend);
this.Controls.Add(this.textBoxDate);
this.Controls.Add(this.labelDate);
this.Controls.Add(this.buttonReply);
this.Controls.Add(this.buttonClose);
this.Controls.Add(this.textBoxBody);
this.Controls.Add(this.labelBody);
this.Controls.Add(this.textBoxSubject);
this.Controls.Add(this.labelSubject);
this.Controls.Add(this.labelAdress);
this.Controls.Add(this.textBoxEmail);
this.Name = "FormLetter";
this.Text = "Письмо";
this.Load += new System.EventHandler(this.FormLetter_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private TextBox textBoxEmail;
private Label labelAdress;
private Label labelSubject;
private TextBox textBoxSubject;
private Label labelBody;
private TextBox textBoxBody;
private Button buttonClose;
private Button buttonReply;
private Label labelDate;
private TextBox textBoxDate;
private Button buttonSend;
}
}

View File

@ -0,0 +1,152 @@
using Microsoft.Extensions.Logging;
using Pizzeria;
using PizzeriaBusinessLogic.MailWorker;
using PizzeriaContracts.BindingModels;
using PizzeriaContracts.BusinessLogicsContracts;
using PizzeriaContracts.SearchModels;
using PizzeriaContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace PizzeriaView
{
public partial class FormLetter : Form
{
private readonly ILogger _logger;
private readonly IMessageInfoLogic _logic;
private readonly AbstractMailWorker _worker;
public MessageInfoViewModel? model;
public string? messageId;
public FormLetter(ILogger<FormLetter> logger, IMessageInfoLogic logic, AbstractMailWorker worker)
{
InitializeComponent();
_logger = logger;
_logic = logic;
_worker = worker;
}
private void FormLetter_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(messageId))
{
ReloadLetter();
return;
}
else if (model != null)
{
ConfigurateToCreateAnsver();
return;
}
_logger.LogError("Для формы не переданно сведений о письме, на которое отвечаем!");
DialogResult = DialogResult.Abort;
Close();
return;
}
private void ReloadLetter()
{
_logger.LogInformation("Загрузка существующего письма с id:{}", messageId);
model = _logic.ReadElement(new MessageInfoSearchModel
{
MessageId = messageId
});
if (model != null)
{
_logger.LogInformation("Письмо найдено");
textBoxEmail.Text = model.SenderName;
textBoxDate.Text = model.DateDelivery.ToString();
textBoxSubject.Text = model.Subject;
textBoxBody.Text = model.Body;
if (model.IsReply)
{
_logger.LogInformation("Письмо само и есть ответ");
buttonReply.Visible = false;
}
else
{
if (!string.IsNullOrEmpty(model.ReplyMessageId))
{
_logger.LogInformation("У письма есть ответ.");
buttonReply.Text = "Прочитать ответ";
}
}
return;
}
_logger.LogWarning("Письмо с таким id не удалось найти");
DialogResult = DialogResult.Abort;
Close();
return;
}
private void ConfigurateToCreateAnsver()
{
textBoxEmail.Text = model.SenderName;
labelDate.Visible = false;
textBoxDate.Visible = false;
textBoxSubject.Text = $"re: {model.Subject}";
textBoxBody.ReadOnly = false;
buttonReply.Visible = false;
buttonSend.Visible = true;
_logger.LogInformation("Запущена форма создания нового письма - ответа");
}
private void buttonClose_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void buttonReply_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormLetter));
if (service is FormLetter form)
{
if (!string.IsNullOrEmpty(model.ReplyMessageId))
{
form.messageId = model.ReplyMessageId;
}
else
{
form.model = model;
}
if (form.ShowDialog() != DialogResult.Cancel)
{
buttonReply.Visible = false;
}
}
}
private void buttonSend_Click(object sender, EventArgs e)
{
if (model == null)
{
return;
}
string subject = textBoxSubject.Text;
string text = textBoxBody.Text;
Task.Run(() => _worker.MailSendReplyAsync(new MailReplySendInfoBindingModel
{
MailAddress = model.SenderName,
Subject = subject,
Text = text,
ParentMessageId = model.MessageId,
}));
DialogResult = DialogResult.OK;
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

@ -28,10 +28,26 @@
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
this.panel1 = new System.Windows.Forms.Panel();
this.dataGridView = new System.Windows.Forms.DataGridView(); this.dataGridView = new System.Windows.Forms.DataGridView();
this.buttonOpen = new System.Windows.Forms.Button();
this.numericUpDownPage = new System.Windows.Forms.NumericUpDown();
this.buttonPreveous = new System.Windows.Forms.Button();
this.buttonNext = new System.Windows.Forms.Button();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownPage)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// panel1
//
this.panel1.Controls.Add(this.dataGridView);
this.panel1.Location = new System.Drawing.Point(3, 1);
this.panel1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(795, 431);
this.panel1.TabIndex = 0;
//
// dataGridView // dataGridView
// //
this.dataGridView.AllowUserToAddRows = false; this.dataGridView.AllowUserToAddRows = false;
@ -43,25 +59,75 @@
this.dataGridView.ReadOnly = true; this.dataGridView.ReadOnly = true;
this.dataGridView.RowHeadersWidth = 51; this.dataGridView.RowHeadersWidth = 51;
this.dataGridView.RowTemplate.Height = 29; this.dataGridView.RowTemplate.Height = 29;
this.dataGridView.Size = new System.Drawing.Size(786, 270); this.dataGridView.Size = new System.Drawing.Size(795, 431);
this.dataGridView.TabIndex = 0; this.dataGridView.TabIndex = 2;
//
// buttonOpen
//
this.buttonOpen.Location = new System.Drawing.Point(806, 80);
this.buttonOpen.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.buttonOpen.Name = "buttonOpen";
this.buttonOpen.Size = new System.Drawing.Size(107, 31);
this.buttonOpen.TabIndex = 1;
this.buttonOpen.Text = "Прочитать";
this.buttonOpen.UseVisualStyleBackColor = true;
this.buttonOpen.Click += new System.EventHandler(this.buttonOpen_Click);
//
// numericUpDownPage
//
this.numericUpDownPage.Location = new System.Drawing.Point(825, 287);
this.numericUpDownPage.Name = "numericUpDownPage";
this.numericUpDownPage.Size = new System.Drawing.Size(85, 27);
this.numericUpDownPage.TabIndex = 4;
this.numericUpDownPage.ValueChanged += new System.EventHandler(this.numericUpDownPage_ValueChanged);
//
// buttonPreveous
//
this.buttonPreveous.Location = new System.Drawing.Point(825, 323);
this.buttonPreveous.Name = "buttonPreveous";
this.buttonPreveous.Size = new System.Drawing.Size(39, 29);
this.buttonPreveous.TabIndex = 5;
this.buttonPreveous.Text = "<-";
this.buttonPreveous.UseVisualStyleBackColor = true;
this.buttonPreveous.Click += new System.EventHandler(this.buttonPreveous_Click);
//
// buttonNext
//
this.buttonNext.Location = new System.Drawing.Point(872, 323);
this.buttonNext.Name = "buttonNext";
this.buttonNext.Size = new System.Drawing.Size(39, 29);
this.buttonNext.TabIndex = 6;
this.buttonNext.Text = "->";
this.buttonNext.UseVisualStyleBackColor = true;
this.buttonNext.Click += new System.EventHandler(this.buttonNext_Click);
// //
// FormMail // FormMail
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(786, 270); this.ClientSize = new System.Drawing.Size(925, 428);
this.Controls.Add(this.dataGridView); this.Controls.Add(this.buttonNext);
this.Controls.Add(this.buttonPreveous);
this.Controls.Add(this.numericUpDownPage);
this.Controls.Add(this.buttonOpen);
this.Controls.Add(this.panel1);
this.Name = "FormMail"; this.Name = "FormMail";
this.Text = "Письма"; this.Text = "Письма";
this.Load += new System.EventHandler(this.FormMail_Load); this.Load += new System.EventHandler(this.FormMail_Load);
this.panel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownPage)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
} }
#endregion #endregion
private Panel panel1;
private DataGridView dataGridView; private DataGridView dataGridView;
private Button buttonOpen;
private NumericUpDown numericUpDownPage;
private Button buttonPreveous;
private Button buttonNext;
} }
} }

View File

@ -1,5 +1,10 @@
using Microsoft.Extensions.Logging; using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.Extensions.Logging;
using Pizzeria;
using PizzeriaBusinessLogic.BusinessLogics;
using PizzeriaContracts.BindingModels;
using PizzeriaContracts.BusinessLogicsContracts; using PizzeriaContracts.BusinessLogicsContracts;
using PizzeriaContracts.SearchModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
@ -16,6 +21,8 @@ namespace PizzeriaView
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IMessageInfoLogic _logic; private readonly IMessageInfoLogic _logic;
private int currentPage = 1;
private int pageLength = 2;
public FormMail(ILogger<FormMail> logger, IMessageInfoLogic logic) public FormMail(ILogger<FormMail> logger, IMessageInfoLogic logic)
{ {
@ -28,12 +35,21 @@ namespace PizzeriaView
{ {
try try
{ {
var list = _logic.ReadList(null); var list = _logic.ReadList(new MessageInfoSearchModel()
{
PageLength = pageLength,
PageIndex = currentPage
});
numericUpDownPage.Value = pageLength;
if (list != null) if (list != null)
{ {
dataGridView.DataSource = list; dataGridView.DataSource = list;
dataGridView.Columns["MessageId"].Visible = false; dataGridView.Columns["MessageId"].Visible = false;
dataGridView.Columns["ClientId"].Visible = false; dataGridView.Columns["ClientId"].Visible = false;
dataGridView.Columns["ReplyMessageId"].Visible = false;
dataGridView.Columns["Reply"].Visible = false;
dataGridView.Columns["IsReply"].Visible = false;
dataGridView.Columns["Body"].AutoSizeMode = dataGridView.Columns["Body"].AutoSizeMode =
DataGridViewAutoSizeColumnMode.Fill; DataGridViewAutoSizeColumnMode.Fill;
} }
@ -50,5 +66,50 @@ namespace PizzeriaView
{ {
LoadData(); LoadData();
} }
private void buttonOpen_Click(object sender, EventArgs e)
{
if (dataGridView.SelectedRows.Count <= 0)
return;
var service = Program.ServiceProvider?.GetService(typeof(FormLetter));
if (service is FormLetter form)
{
string? messageId = dataGridView.SelectedRows[0].Cells["MessageId"].Value.ToString();
if (messageId == null) return;
form.messageId = messageId;
if (!Convert.ToBoolean(dataGridView.SelectedRows[0].Cells["IsReaded"].Value))
{
_logic.Update(new MessageInfoBindingModel
{
MessageId = messageId,
IsReaded = true,
ReplyMessageId = dataGridView.SelectedRows[0].Cells["ReplyMessageId"].Value?.ToString()
});
}
form.ShowDialog();
LoadData();
}
}
private void buttonPreveous_Click(object sender, EventArgs e)
{
currentPage = Math.Max(1, currentPage - 1);
LoadData();
}
private void buttonNext_Click(object sender, EventArgs e)
{
currentPage++;
LoadData();
}
private void numericUpDownPage_ValueChanged(object sender, EventArgs e)
{
pageLength = Math.Max(1, (int)numericUpDownPage.Value);
LoadData();
}
} }
} }

View File

@ -250,7 +250,6 @@ namespace PizzeriaView
form.ShowDialog(); form.ShowDialog();
} }
} }
}
private void InfoToolStripMenuItem_Click(object sender, EventArgs e) private void InfoToolStripMenuItem_Click(object sender, EventArgs e)
{ {