PIbd - 21 Bakalskaya E.D. LabWork07 BASE #13

Closed
ekallin wants to merge 26 commits from LabWork07 into LabWork06
45 changed files with 1338 additions and 31 deletions

12
SushiBar/App.config Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SmtpClientHost" value="smtp.beget.com" />
<add key="SmtpClientPort" value="2525" />
<add key="PopHost" value="pop3.beget.com" />
<add key="PopPort" value="995" />
<add key="MailLogin" value="sushishop@ekallin.ru" />
<add key="MailPassword" value="8j#HWiCBiI*I" />
</appSettings>
</configuration>

65
SushiBar/FormMails.Designer.cs generated Normal file
View File

@ -0,0 +1,65 @@
namespace SushiBarView
{
partial class FormMails
{
/// <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();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
//
// dataGridView
//
dataGridView.BackgroundColor = Color.SkyBlue;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Dock = DockStyle.Fill;
dataGridView.Location = new Point(0, 0);
dataGridView.Name = "dataGridView";
dataGridView.RowHeadersVisible = false;
dataGridView.RowHeadersWidth = 51;
dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView.Size = new Size(800, 450);
dataGridView.TabIndex = 0;
//
// FormMails
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(dataGridView);
Name = "FormMails";
Text = "Список писем";
Load += FormMails_Load;
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView;
}
}

44
SushiBar/FormMails.cs Normal file
View File

@ -0,0 +1,44 @@
using Microsoft.Extensions.Logging;
using SushiBarContracts.BusinessLogicsContracts;
namespace SushiBarView
{
public partial class FormMails : Form
{
private readonly ILogger logger;
private readonly IMessageInfoLogic messageInfoLogic;
public FormMails(ILogger<FormMails> logger, IMessageInfoLogic messageInfoLogic)
{
this.logger = logger;
this.messageInfoLogic = messageInfoLogic;
InitializeComponent();
}
private void LoadData()
{
try
{
var list = messageInfoLogic.ReadList(null);
if (list != null)
{
dataGridView.DataSource = list;
dataGridView.Columns["ClientId"].Visible = false;
dataGridView.Columns["MessageId"].Visible = false;
dataGridView.Columns["Body"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
logger.LogInformation("Load list of mails");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK);
logger.LogError("Load list of mails failed");
}
}
private void FormMails_Load(object sender, EventArgs e)
{
LoadData();
}
}
}

120
SushiBar/FormMails.resx Normal file
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

@ -43,6 +43,7 @@
buttonCreateOrder = new Button();
buttonOrderIssued = new Button();
buttonRefreshOrders = new Button();
списокПисемToolStripMenuItem = new ToolStripMenuItem();
menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
@ -50,7 +51,7 @@
// menuStrip1
//
menuStrip1.ImageScalingSize = new Size(20, 20);
menuStrip1.Items.AddRange(new ToolStripItem[] { ToolStripMenuItemRef, отчетыToolStripMenuItem, клиентыToolStripMenuItem, исполнителиToolStripMenuItem, запускРаботToolStripMenuItem });
menuStrip1.Items.AddRange(new ToolStripItem[] { ToolStripMenuItemRef, отчетыToolStripMenuItem, клиентыToolStripMenuItem, исполнителиToolStripMenuItem, запускРаботToolStripMenuItem, списокПисемToolStripMenuItem });
menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1";
menuStrip1.Size = new Size(1316, 28);
@ -174,6 +175,13 @@
buttonRefreshOrders.UseVisualStyleBackColor = true;
buttonRefreshOrders.Click += ButtonRef_Click;
//
// списокПисемToolStripMenuItem
//
списокПисемToolStripMenuItem.Name = "списокПисемToolStripMenuItem";
списокПисемToolStripMenuItem.Size = new Size(121, 24);
списокПисемToolStripMenuItem.Text = "Список писем";
списокПисемToolStripMenuItem.Click += списокПисемToolStripMenuItem_Click;
//
// FormMain
//
AutoScaleDimensions = new SizeF(8F, 20F);
@ -214,5 +222,6 @@
private ToolStripMenuItem клиентыToolStripMenuItem;
private ToolStripMenuItem исполнителиToolStripMenuItem;
private ToolStripMenuItem запускРаботToolStripMenuItem;
private ToolStripMenuItem списокПисемToolStripMenuItem;
}
}

View File

@ -162,5 +162,14 @@ namespace SushiBarView
_workProcess.DoWork((Program.ServiceProvider?.GetService(typeof(IImplementerLogic)) as IImplementerLogic)!, _orderLogic);
MessageBox.Show("Процесс обработки запущен", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void списокПисемToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormMails));
if(service is FormMails form)
{
form.ShowDialog();
}
}
}
}

View File

@ -1,10 +1,13 @@
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using SushiBarBusinessLogic;
using SushiBarBusinessLogic.BusinessLogic;
using SushiBarBusinessLogic.MailWorker;
using SushiBarBusinessLogic.OfficePackage;
using SushiBarBusinessLogic.OfficePackage.Implements;
using SushiBarContracts.BindingModel;
using SushiBarContracts.BusinessLogicsContracts;
using SushiBarContracts.StoragesContracts;
using SushiBarDatabaseImplement.Implements;
@ -30,11 +33,28 @@ namespace SushiBar
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
var services = new ServiceCollection();
// Добавлено для устранения ошибки с кодировкой при сохранении в PDF
// чтобы заработало нужно поставить NuGet пакет System.Text.Encoding.CodePages
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider();
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, 5000);
}
catch (Exception ex)
{
var logger = _serviceProvider.GetService<ILogger>();
logger?.LogError(ex, "Îøèáêà ðàáîòû ñ ïî÷òîé");
}
Application.Run(_serviceProvider.GetRequiredService<FormMain>());
}
@ -50,6 +70,7 @@ namespace SushiBar
services.AddTransient<ISushiStorage, SushiStorage>();
services.AddTransient<IClientStorage, ClientStorage>();
services.AddTransient<IImplementerStorage, ImplementerStorage>();
services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
services.AddTransient<IComponentLogic, ComponentLogic>();
services.AddTransient<IOrderLogic, OrderLogic>();
@ -58,7 +79,9 @@ namespace SushiBar
services.AddTransient<IReportLogic, ReportLogic>();
services.AddTransient<IWorkProcess, WorkModeling>();
services.AddTransient<IImplementerLogic, ImplementerLogic>();
services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
services.AddSingleton<AbstractMailWorker, MailKitWorker>();
services.AddTransient<AbstractSaveToExcel, SaveToExcel>();
services.AddTransient<AbstractSaveToWord, SaveToWord>();
services.AddTransient<AbstractSaveToPdf, SaveToPdf>();
@ -75,7 +98,8 @@ namespace SushiBar
services.AddTransient<FormReportSushiComponent>();
services.AddTransient<FormImplementer>();
services.AddTransient<FormImplementers>();
services.AddTransient<FormMails>();
}
private static void MailCheck(object obj) => ServiceProvider?.GetService<AbstractMailWorker>()?.MailCheck();
}
}

View File

@ -4,6 +4,7 @@ using SushiBarContracts.BusinessLogicsContracts;
using SushiBarContracts.SearchModel;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;
using System.Text.RegularExpressions;
namespace SushiBarBusinessLogic
{
@ -92,11 +93,11 @@ namespace SushiBarBusinessLogic
{
throw new ArgumentNullException("Invalid fullname of user", 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("Invalid email of user", 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("Invalid password of user", nameof(model.Password));
}

View File

@ -0,0 +1,77 @@
using Microsoft.Extensions.Logging;
using SushiBarContracts.BindingModel;
using SushiBarContracts.BusinessLogicsContracts;
namespace SushiBarBusinessLogic.MailWorker
{
public abstract class AbstractMailWorker
{
protected string _mailLogin = string.Empty;
protected string _mailPassword = string.Empty;
protected string _smtpClientHost = string.Empty;
protected int _smtpClientPort;
protected string _popHost = string.Empty;
protected int _popPort;
private readonly IMessageInfoLogic _messageInfoLogic;
private readonly ILogger _logger;
public AbstractMailWorker(ILogger<AbstractMailWorker> logger,
IMessageInfoLogic messageInfoLogic)
{
_logger = logger;
_messageInfoLogic = messageInfoLogic;
}
public void MailConfig(MailConfigBindingModel config)
{
_mailLogin = config.MailLogin;
_mailPassword = config.MailPassword;
_smtpClientHost = config.SmtpClientHost;
_smtpClientPort = config.SmtpClientPort;
_popHost = config.PopHost;
_popPort = config.PopPort;
_logger.LogDebug($"Config: {_mailLogin}, {_mailPassword}, " +
$"{_smtpClientHost}, {_smtpClientPort}, {_popHost}, {_popPort}");
}
public async void MailSendAsync(MailSendInfoBindingModel info)
{
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{
return;
}
if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0)
{
return;
}
if (string.IsNullOrEmpty(info.MailAddress) ||
string.IsNullOrEmpty(info.Subject) ||
string.IsNullOrEmpty(info.Text))
{
return;
}
_logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject);
await SendMailAsync(info);
}
public async void MailCheck()
{
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{
return;
}
if (string.IsNullOrEmpty(_popHost) || _popPort == 0)
{
return;
}
if (_messageInfoLogic == null)
{
return;
}
var list = await ReceiveMailAsync();
_logger.LogDebug("Check Mail: {Count} new mails", list.Count);
foreach (var mail in list)
{
_messageInfoLogic.Create(mail);
}
}
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
protected abstract Task<List<MessageInfoBindingModel>> ReceiveMailAsync();
}
}

View File

@ -0,0 +1,75 @@
using Microsoft.Extensions.Logging;
using SushiBarContracts.BindingModel;
using SushiBarContracts.BusinessLogicsContracts;
using MailKit.Net.Pop3;
using MailKit.Security;
using System.Net.Mail;
using System.Text;
using System.Net;
namespace SushiBarBusinessLogic.MailWorker
{
public class MailKitWorker : AbstractMailWorker
{
public MailKitWorker(ILogger<MailKitWorker> logger, IMessageInfoLogic messageInfoLogic)
: base(logger, messageInfoLogic) { }
protected override async Task SendMailAsync(MailSendInfoBindingModel info)
{
using var objMailMessage = new MailMessage();
using var objSmtpClient = new SmtpClient(_smtpClientHost, _smtpClientPort);
try
{
objMailMessage.From = new MailAddress(_mailLogin);
objMailMessage.To.Add(new MailAddress(info.MailAddress));
objMailMessage.Subject = info.Subject;
objMailMessage.Body = info.Text;
objMailMessage.SubjectEncoding = Encoding.UTF8;
objMailMessage.BodyEncoding = Encoding.UTF8;
objSmtpClient.UseDefaultCredentials = false;
objSmtpClient.EnableSsl = true;
objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
objSmtpClient.Credentials = new NetworkCredential(_mailLogin, _mailPassword);
await Task.Run(() => objSmtpClient.Send(objMailMessage));
}
catch (Exception)
{
throw;
}
}
protected override async Task<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

@ -0,0 +1,53 @@
using Microsoft.Extensions.Logging;
using SushiBarContracts.BindingModel;
using SushiBarContracts.BusinessLogicsContracts;
using SushiBarContracts.SearchModel;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;
namespace SushiBarBusinessLogic
{
public class MessageInfoLogic : IMessageInfoLogic
{
private readonly ILogger logger;
private readonly IMessageInfoStorage messageStorage;
private readonly IClientLogic clientLogic;
public MessageInfoLogic(ILogger<MessageInfoLogic> logger, IMessageInfoStorage messageStorage, IClientLogic clientLogic)
{
this.logger = logger;
this.messageStorage = messageStorage;
this.clientLogic = clientLogic;
}
public bool Create(MessageInfoBindingModel model)
{
var message = messageStorage.GetElement(new MessageInfoSearchModel { MessageId = model.MessageId});
if (message != null) return false;
var client = clientLogic.ReadElement(new ClientSearchModel{ Email = model.SenderName });
if (client != null)
{
model.ClientId = client.Id;
}
if (messageStorage.Insert(model) == null)
{
logger.LogWarning("Insert message operation failed");
return false;
}
return true;
}
public List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model)
{
var list = model == null ? messageStorage.GetFullList() : messageStorage.GetFilteredList(model);
if (list == null)
{
logger.LogWarning("ReadList had returned a null list");
return null;
}
logger.LogInformation($"ReadList. Count of elements: {list.Count}");
return list;
}
}
}

View File

@ -6,6 +6,7 @@ using SushiBarContracts.ViewModels;
using Microsoft.Extensions.Logging;
using SushiBarDataModels.Enums;
using System.Xml.Linq;
using SushiBarBusinessLogic.MailWorker;
namespace SushiBarBusinessLogic.BusinessLogic
{
@ -13,12 +14,17 @@ namespace SushiBarBusinessLogic.BusinessLogic
{
private readonly ILogger _logger;
private readonly IOrderStorage _orderStorage;
private readonly IClientStorage clientStorage;
private readonly AbstractMailWorker abstractMailWorker;
static readonly object blocking = new object();
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage)
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage,
IClientStorage clientStorage, AbstractMailWorker abstractMailWorker)
{
_logger = logger;
_orderStorage = orderStorage;
this.clientStorage = clientStorage;
this.abstractMailWorker = abstractMailWorker;
}
public OrderViewModel? ReadElement(OrderSearchModel model)
@ -54,13 +60,22 @@ namespace SushiBarBusinessLogic.BusinessLogic
public bool CreateOrder(OrderBindingModel model)
{
CheckModel(model);
if (model.Status != OrderStatus.Неизвестен) return false;
if (model.Status != OrderStatus.Неизвестен)
{
return false;
}
model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null)
var order = _orderStorage.Insert(model);
if (order == null)
{
_logger.LogWarning("Insert operation failed");
return false;
}
var clientView = clientStorage.GetElement(new ClientSearchModel() { Id = order.ClientId });
if (clientView != null)
SendMail(clientView, order);
return true;
}
@ -86,8 +101,7 @@ namespace SushiBarBusinessLogic.BusinessLogic
{
CheckModel(model, false);
var order = _orderStorage.GetElement(new OrderSearchModel { Id = model.Id });
if (order.ImplementerId.HasValue)
model.ImplementerId = order.ImplementerId;
if (order == null)
{
_logger.LogWarning("Change status operation failed. Order not found");
@ -100,6 +114,9 @@ namespace SushiBarBusinessLogic.BusinessLogic
return false;
}
if (order.ImplementerId.HasValue)
model.ImplementerId = order.ImplementerId;
model.Status = orderStatus;
if (model.Status == OrderStatus.Готов)
@ -115,9 +132,45 @@ namespace SushiBarBusinessLogic.BusinessLogic
_logger.LogWarning("Change status operation failed");
return false;
}
var client = clientStorage.GetElement(new ClientSearchModel { Id = order.ClientId });
if (client != null)
SendMail(client, order);
return true;
}
public void SendMail(ClientViewModel clientView, OrderViewModel orderView)
{
if (clientView == null && orderView == null)
{
return;
}
MailSendInfoBindingModel mailSendInfoBindingModel;
if (orderView.Status == OrderStatus.Принят)
{
mailSendInfoBindingModel = new MailSendInfoBindingModel
{
MailAddress = clientView!.Email,
Subject = $"Заказ под номером {orderView.Id}",
Text = $"Ваш заказ под номером {orderView.Id} от {orderView.DateCreate} ценой в {orderView.Sum} тыщ долларов" +
$"был принят"
};
}
else
{
mailSendInfoBindingModel = new MailSendInfoBindingModel
{
MailAddress = clientView!.Email,
Subject = $"Заказ под номером {orderView.Id}",
Text = $"Ваш заказ под номером {orderView.Id} от {orderView.DateCreate} ценой в {orderView.Sum} тыщ долларов " +
$"поменял статус на {orderView.Status}"
};
}
abstractMailWorker.MailSendAsync(mailSendInfoBindingModel);
}
private void CheckModel(OrderBindingModel model, bool withParams = true)
{
if (model == null)
@ -137,8 +190,8 @@ namespace SushiBarBusinessLogic.BusinessLogic
if (model.DateImplement.HasValue && model.DateImplement < model.DateCreate)
throw new ArithmeticException("Заказ должен быть выдан позже, чем был создан");
_logger.LogInformation("Sushi. SushiId:{SushiId}. Count:{ Count}. Sum:{ Sum}. Id: { Id}",
model.SushiId, model.Count, model.Sum, model.Id);
_logger.LogInformation("Sushi. SushiId:{SushiId}. Count:{ Count}. Sum:{ Sum}. Id: { Id}",
model.SushiId, model.Count, model.Sum, model.Id);
}
}
}

View File

@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageReference Include="MailKit" Version="4.5.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.9.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SushiBarClientApp.Models;
using SushiBarContracts.BindingModel;
using SushiBarContracts.ViewModels;
@ -136,5 +137,16 @@ namespace SushiBarClientApp.Controllers
);
return count * (prod?.Price ?? 1);
}
[HttpGet]
public IActionResult Mails()
{
if (APIClient.Client == null)
{
return Redirect("~/Home/Enter");
}
return View(APIClient.GetRequest<List<MessageInfoViewModel>>($"api/client/getmessages?clientId={APIClient.Client.Id}"));
}
}
}

View File

@ -18,4 +18,16 @@
<ProjectReference Include="..\SushiBarContracts\SushiBarContracts.csproj" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Home\Mails.cshtml" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Views\Home\Mails.cshtml" />
</ItemGroup>
<ItemGroup>
<None Include="Views\Home\Mails.cshtml" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,51 @@
@using SushiBarContracts.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>
}
</div>

View File

@ -32,6 +32,9 @@
<li class="nav-item">
<a class="nav-link text-dark" asparea="" asp-controller="Home" asp-action="Register">Регистрация</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asparea="" asp-controller="Home" asp-action="Mails">Письма</a>
</li>
</ul>
</div>
</div>

View File

@ -0,0 +1,12 @@
namespace SushiBarContracts.BindingModel
{
public class MailConfigBindingModel
{
public string MailLogin { get; set; } = string.Empty;
public string MailPassword { get; set; } = string.Empty;
public string SmtpClientHost { get; set; } = string.Empty;
public int SmtpClientPort { get; set; }
public string PopHost { get; set; } = string.Empty;
public int PopPort { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace SushiBarContracts.BindingModel
{
public class MailSendInfoBindingModel
{
public string MailAddress { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
public string Text { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,18 @@
using SushiBarDataModels;
namespace SushiBarContracts.BindingModel
{
public class MessageInfoBindingModel : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; } = DateTime.Now;
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,12 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.SearchModel;
using SushiBarContracts.ViewModels;
namespace SushiBarContracts.BusinessLogicsContracts
{
public interface IMessageInfoLogic
{
List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model);
bool Create(MessageInfoBindingModel model);
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SushiBarContracts.SearchModel
{
public class MessageInfoSearchModel
{
public string? MessageId { get; set; }
public int? ClientId { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.SearchModel;
using SushiBarContracts.ViewModels;
namespace SushiBarContracts.StoragesContracts
{
public interface IMessageInfoStorage
{
List<MessageInfoViewModel> GetFullList();
List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model);
MessageInfoViewModel? GetElement(MessageInfoSearchModel model);
MessageInfoViewModel? Insert(MessageInfoBindingModel model);
}
}

View File

@ -20,7 +20,5 @@ namespace SushiBarContracts.ViewModels
[DisplayName("Пароль")]
public string Password { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,30 @@
using SushiBarDataModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SushiBarContracts.ViewModels
{
public class MessageInfoViewModel : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
[DisplayName("Имя отправителя")]
public string SenderName { get; set; } = string.Empty;
[DisplayName("Дата получения")]
public DateTime DateDelivery { get; set; } = DateTime.Now;
[DisplayName("Тема письма")]
public string Subject { get; set; } = string.Empty;
[DisplayName("Душа письма...")]
public string Body { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SushiBarDataModels
{
public interface IMessageInfoModel
{
string MessageId { get; }
int? ClientId { get; }
string SenderName { get; }
DateTime DateDelivery { get; }
string Subject { get; }
string Body { get; }
}
}

View File

@ -37,14 +37,15 @@ namespace SushiBarDatabaseImplement.Implements
public ClientViewModel? Delete(ClientBindingModel model)
{
using var context = new SushiBarDatabase();
var element = context.Clients.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
var element = context.Clients.FirstOrDefault(c => c.Id == model.Id);
if (element == null)
{
context.Clients.Remove(element);
context.SaveChanges();
return element.GetViewModel;
return null;
}
return null;
context.Clients.Remove(element);
context.SaveChanges();
return element.GetViewModel;
}
public ClientViewModel? GetElement(ClientSearchModel model)

View File

@ -0,0 +1,63 @@
using Microsoft.EntityFrameworkCore;
using SushiBarContracts.BindingModel;
using SushiBarContracts.SearchModel;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;
using SushiBarDatabaseImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SushiBarDatabaseImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
using var context = new SushiBarDatabase();
if(string.IsNullOrEmpty(model.MessageId)) return null;
return context.Messages
.Include(x => x.Client)
.FirstOrDefault(x => x.MessageId == model.MessageId)?
.GetViewModel;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
using var context = new SushiBarDatabase();
if (model.ClientId.HasValue)
{
return context.Messages
.Include(x => x.Client)
.Where(x => x.ClientId == model.ClientId)
.Select(x => x.GetViewModel)
.ToList();
}
return new();
}
public List<MessageInfoViewModel> GetFullList()
{
using var context = new SushiBarDatabase();
return context.Messages
.Include(x => x.Client)
.Select(x => x.GetViewModel)
.ToList();
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
using var context = new SushiBarDatabase();
var message = MessageInfo.Create(model);
if (message == null)
{
return null;
}
context.Messages.Add(message);
context.SaveChanges();
return message.GetViewModel;
}
}
}

View File

@ -12,7 +12,7 @@ using SushiBarDatabaseImplement;
namespace SushiBarDatabaseImplement.Migrations
{
[DbContext(typeof(SushiBarDatabase))]
[Migration("20240421075923_InitCreate")]
[Migration("20240505111335_InitCreate")]
partial class InitCreate
{
/// <inheritdoc />
@ -97,6 +97,36 @@ namespace SushiBarDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("SushiBarDatabaseImplement.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<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("SushiBarDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -186,6 +216,15 @@ namespace SushiBarDatabaseImplement.Migrations
b.ToTable("SushiComponents");
});
modelBuilder.Entity("SushiBarDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("SushiBarDatabaseImplement.Models.Client", "Client")
.WithMany()
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("SushiBarDatabaseImplement.Models.Order", b =>
{
b.HasOne("SushiBarDatabaseImplement.Models.Client", "Client")

View File

@ -70,6 +70,27 @@ namespace SushiBarDatabaseImplement.Migrations
table.PrimaryKey("PK_Sushis", x => x.Id);
});
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.CreateTable(
name: "Orders",
columns: table => new
@ -134,6 +155,11 @@ namespace SushiBarDatabaseImplement.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Messages_ClientId",
table: "Messages",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_Orders_ClientId",
table: "Orders",
@ -163,6 +189,9 @@ namespace SushiBarDatabaseImplement.Migrations
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Messages");
migrationBuilder.DropTable(
name: "Orders");

View File

@ -12,8 +12,8 @@ using SushiBarDatabaseImplement;
namespace SushiBarDatabaseImplement.Migrations
{
[DbContext(typeof(SushiBarDatabase))]
[Migration("20240422075953_ClearOrders")]
partial class ClearOrders
[Migration("20240505151023_forMistake")]
partial class forMistake
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -97,6 +97,36 @@ namespace SushiBarDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("SushiBarDatabaseImplement.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<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("SushiBarDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -186,6 +216,15 @@ namespace SushiBarDatabaseImplement.Migrations
b.ToTable("SushiComponents");
});
modelBuilder.Entity("SushiBarDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("SushiBarDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("SushiBarDatabaseImplement.Models.Order", b =>
{
b.HasOne("SushiBarDatabaseImplement.Models.Client", "Client")
@ -232,6 +271,8 @@ namespace SushiBarDatabaseImplement.Migrations
modelBuilder.Entity("SushiBarDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});

View File

@ -5,12 +5,11 @@
namespace SushiBarDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class ClearOrders : Migration
public partial class forMistake : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DELETE FROM Orders");
}

View File

@ -94,6 +94,36 @@ namespace SushiBarDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("SushiBarDatabaseImplement.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<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("SushiBarDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -183,6 +213,15 @@ namespace SushiBarDatabaseImplement.Migrations
b.ToTable("SushiComponents");
});
modelBuilder.Entity("SushiBarDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("SushiBarDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("SushiBarDatabaseImplement.Models.Order", b =>
{
b.HasOne("SushiBarDatabaseImplement.Models.Client", "Client")
@ -229,6 +268,8 @@ namespace SushiBarDatabaseImplement.Migrations
modelBuilder.Entity("SushiBarDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});

View File

@ -24,6 +24,9 @@ namespace SushiBarDatabaseImplement.Models
[ForeignKey("ClientId")]
public virtual List<Order> Orders { get; set; } = new();
[ForeignKey("ClientId")]
public virtual List<MessageInfo> Messages { get; set; } = new();
public static Client? Create(ClientBindingModel? model)
{
if (model == null)

View File

@ -0,0 +1,53 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.ViewModels;
using SushiBarDataModels;
using System.ComponentModel.DataAnnotations;
namespace SushiBarDatabaseImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
[Key]
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
[Required]
public string SenderName { get; set; } = string.Empty;
[Required]
public DateTime DateDelivery { get; set; } = DateTime.Now;
[Required]
public string Subject { get; set; } = string.Empty;
[Required]
public string Body { get; set; } = string.Empty;
public virtual Client? Client { get; set; }
public static MessageInfo? Create(MessageInfoBindingModel model)
{
if(model == null) return null;
return new MessageInfo
{
MessageId = model.MessageId,
ClientId = model.ClientId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
Subject = model.Subject,
Body = model.Body,
};
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
};
}
}

View File

@ -26,5 +26,6 @@ namespace SushiBarDatabaseImplement
public virtual DbSet<Order> Orders { set; get; }
public virtual DbSet<Client> Clients { set; get; }
public virtual DbSet<Implementer> Implementers { set; get; }
public virtual DbSet<MessageInfo> Messages { set; get; }
}
}

View File

@ -17,11 +17,14 @@ namespace SushiBarFileImplement
private readonly string ImplementerFileName = "Implementer.xml";
private readonly string MessageInfoFileName = "MessageInfo.xml";
public List<Component> Components { get; private set; }
public List<Order> Orders { get; private set; }
public List<Sushi> Sushis { get; private set; }
public List<Client> Clients { get; private set; }
public List<Implementer> Implementers { get; private set; }
public List<MessageInfo> Messages { get; private set; }
public static DataFileSingleton GetInstance()
{
@ -37,6 +40,7 @@ namespace SushiBarFileImplement
public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement);
public void SaveClients() => SaveData(Clients, ClientFileName, "Clients", x => x.GetXElement);
public void SaveImplementers() => SaveData(Implementers, ImplementerFileName, "Implementers", x => x.GetXElement);
public void SaveMessageInfo() => SaveData(Messages, MessageInfoFileName, "Messages", x => x.GetXElement);
private DataFileSingleton()
{
@ -45,6 +49,7 @@ namespace SushiBarFileImplement
Orders = LoadData(OrderFileName, "Order", x => Order.Create(x)!)!;
Clients = LoadData(ClientFileName, "Client", x => Client.Create(x)!)!;
Implementers = LoadData(ImplementerFileName, "Implementer", x => Implementer.Create(x)!)!;
Messages = LoadData(MessageInfoFileName, "MessageInfo", x => MessageInfo.Create(x)!)!;
}
private static List<T>? LoadData<T>(string filename, string xmlNodeName, Func<XElement, T> selectFunction)

View File

@ -0,0 +1,49 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.SearchModel;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;
using SushiBarFileImplement.Models;
namespace SushiBarFileImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
private readonly DataFileSingleton source;
public MessageInfoStorage()
{
source = DataFileSingleton.GetInstance();
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if (string.IsNullOrEmpty(model.MessageId)) return null;
return source.Messages.FirstOrDefault(x => x.MessageId.Equals(model.MessageId))?.GetViewModel;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
if (!model.ClientId.HasValue)
{
return new();
}
return source.Messages.Where(x => x.ClientId == model.ClientId).Select(x => x.GetViewModel).ToList();
}
public List<MessageInfoViewModel> GetFullList()
{
return source.Messages.Select(x => x.GetViewModel).ToList();
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
var newMessage = MessageInfo.Create(model);
if(newMessage == null)
{
return null;
}
source.Messages.Add(newMessage);
source.SaveMessageInfo();
return newMessage.GetViewModel;
}
}
}

View File

@ -0,0 +1,73 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.ViewModels;
using SushiBarDataModels;
using System.Xml.Linq;
namespace SushiBarFileImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; } = DateTime.Now;
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel model)
{
if (model == null) return null;
return new MessageInfo
{
MessageId = model.MessageId,
ClientId = model.ClientId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
Subject = model.Subject,
Body = model.Body,
};
}
public static MessageInfo? Create(XElement element)
{
if (element == null)
{
return null;
}
return new MessageInfo()
{
MessageId = element.Attribute("MessageId")!.Value,
ClientId = Convert.ToInt32(element.Attribute("ClientId")!.Value),
SenderName = element.Element("SenderName")!.Value,
DateDelivery = Convert.ToDateTime(element.Element("DateDelivery")!.Value),
Subject = element.Attribute("Subject")!.Value,
Body = element.Attribute("Body")!.Value,
};
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
};
public XElement GetXElement =>
new("MessageInfo",
new XAttribute("MessageId", MessageId),
new XElement("ClientId", ClientId),
new XElement("SenderName", SenderName),
new XElement("DateDelivery", DateDelivery),
new XElement("Subject", Subject),
new XElement("Body", Body)
);
}
}

View File

@ -10,6 +10,7 @@ namespace SushiBarListImplement
public List<Sushi> Sushis { get; set; }
public List<Client> Clients { get; set; }
public List<Implementer> Implementers { get; set; }
public List<MessageInfo> Messages { get; set; }
private DataListSingleton()
{
Components = new List<Component>();
@ -17,6 +18,7 @@ namespace SushiBarListImplement
Sushis = new List<Sushi>();
Clients = new List<Client>();
Implementers = new List<Implementer>();
Messages = new List<MessageInfo>();
}
public static DataListSingleton GetInstance()
{

View File

@ -0,0 +1,71 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.SearchModel;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;
using SushiBarListImplement;
using SushiBarListImplements.Models;
namespace SushiBarListImplements.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
private readonly DataListSingleton source;
public MessageInfoStorage(DataListSingleton source)
{
this.source = source;
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if(string.IsNullOrEmpty(model.MessageId) || !model.ClientId.HasValue)
{
return null;
}
foreach (var message in source.Messages)
{
if (message.MessageId.Equals(model.MessageId))
{
return message.GetViewModel;
}
}
return null;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
var list = new List<MessageInfoViewModel>();
foreach (var msg in source.Messages)
{
if (msg.ClientId.HasValue && model.ClientId == msg.ClientId)
{
list.Add(msg.GetViewModel);
}
}
return list;
}
public List<MessageInfoViewModel> GetFullList()
{
var list = new List<MessageInfoViewModel>();
foreach (var msg in source.Messages)
{
list.Add(msg.GetViewModel);
}
return list;
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
var newMessage = MessageInfo.Create(model);
if (newMessage == null)
{
return null;
}
source.Messages.Add(newMessage);
return newMessage.GetViewModel;
}
}
}

View File

@ -0,0 +1,45 @@
using SushiBarContracts.BindingModel;
using SushiBarContracts.ViewModels;
using SushiBarDataModels;
namespace SushiBarListImplements.Models
{
public class MessageInfo : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; } = DateTime.Now;
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel? model)
{
if (model == null) return null;
return new MessageInfo
{
MessageId = model.MessageId,
ClientId = model.ClientId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
Subject = model.Subject,
Body = model.Body,
};
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
};
}
}

View File

@ -12,11 +12,12 @@ namespace SushiBarRestApi.Controllers
{
private readonly ILogger _logger;
private readonly IClientLogic _logic;
public ClientController(IClientLogic logic, ILogger<ClientController>
logger)
private readonly IMessageInfoLogic messageLogic;
public ClientController(IClientLogic logic, ILogger<ClientController> logger, IMessageInfoLogic messageLogic)
{
_logger = logger;
_logic = logic;
this.messageLogic = messageLogic;
}
[HttpGet]
public ClientViewModel? Login(string login, string password)
@ -61,5 +62,23 @@ namespace SushiBarRestApi.Controllers
throw;
}
}
[HttpGet]
public List<MessageInfoViewModel>? GetMessages(int clientId)
{
try
{
return messageLogic.ReadList(new MessageInfoSearchModel
{
ClientId = clientId
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения писем клиента");
throw;
}
}
}
}

View File

@ -4,6 +4,8 @@ using SushiBarDatabaseImplement.Implements;
using Microsoft.OpenApi.Models;
using SushiBarBusinessLogic.BusinessLogic;
using SushiBarBusinessLogic;
using SushiBarBusinessLogic.MailWorker;
using SushiBarContracts.BindingModel;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
@ -12,9 +14,14 @@ builder.Logging.AddLog4Net("log4net.config");
builder.Services.AddTransient<IClientStorage, ClientStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<ISushiStorage, SushiStorage>();
builder.Services.AddTransient<IImplementerStorage, ImplementerStorage>();
builder.Services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<ISushiLogic, SushiLogic>();
builder.Services.AddTransient<IImplementerLogic, ImplementerLogic>();
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
builder.Services.AddEndpointsApiExplorer();
@ -27,6 +34,16 @@ 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())
{
@ -36,4 +53,4 @@ if (app.Environment.IsDevelopment())
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
app.Run();

View File

@ -5,5 +5,13 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"SmtpClientHost": "smtp.beget.com",
"SmtpClientPort": "2525",
"PopHost": "pop.beget.com",
"PopPort": "995",
"MailLogin": "sushishop@ekallin.ru",
"MailPassword": "8j#HWiCBiI*I"
}