Вродь сделал

This commit is contained in:
gg12 darfren 2024-04-29 18:33:41 +04:00
parent 8f451e7d7f
commit 2e5c36d63b
40 changed files with 1317 additions and 31 deletions

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SmtpClientHost" value="smtp.gmail.com" />
<add key="SmtpClientPort" value="587" />
<add key="PopHost" value="pop.gmail.com" />
<add key="PopPort" value="995" />
<add key="MailLogin" value="sasda3183@gmail.com" />
<add key="MailPassword" value="ozxp vjof uinv fcmj" />
</appSettings>
</configuration>

View File

@ -38,11 +38,12 @@
списокМороженногоToolStripMenuItem = new ToolStripMenuItem(); списокМороженногоToolStripMenuItem = new ToolStripMenuItem();
компонентыПоМороженнымToolStripMenuItem = new ToolStripMenuItem(); компонентыПоМороженнымToolStripMenuItem = new ToolStripMenuItem();
списокЗаказовToolStripMenuItem = new ToolStripMenuItem(); списокЗаказовToolStripMenuItem = new ToolStripMenuItem();
запускРаботToolStripMenuItem = new ToolStripMenuItem();
DataGridView = new DataGridView(); DataGridView = new DataGridView();
CreateOrderButton = new Button(); CreateOrderButton = new Button();
IssuedButton = new Button(); IssuedButton = new Button();
RefreshButton = new Button(); RefreshButton = new Button();
запускРаботToolStripMenuItem = new ToolStripMenuItem(); почтаToolStripMenuItem = new ToolStripMenuItem();
menuStrip1.SuspendLayout(); menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)DataGridView).BeginInit(); ((System.ComponentModel.ISupportInitialize)DataGridView).BeginInit();
SuspendLayout(); SuspendLayout();
@ -50,7 +51,7 @@
// menuStrip1 // menuStrip1
// //
menuStrip1.ImageScalingSize = new Size(20, 20); menuStrip1.ImageScalingSize = new Size(20, 20);
menuStrip1.Items.AddRange(new ToolStripItem[] { ToolStripMenu, отчетыToolStripMenuItem, запускРаботToolStripMenuItem }); menuStrip1.Items.AddRange(new ToolStripItem[] { ToolStripMenu, отчетыToolStripMenuItem, запускРаботToolStripMenuItem, почтаToolStripMenuItem });
menuStrip1.Location = new Point(0, 0); menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1"; menuStrip1.Name = "menuStrip1";
menuStrip1.Padding = new Padding(6, 3, 0, 3); menuStrip1.Padding = new Padding(6, 3, 0, 3);
@ -121,6 +122,13 @@
списокЗаказовToolStripMenuItem.Text = "Список заказов"; списокЗаказовToolStripMenuItem.Text = "Список заказов";
списокЗаказовToolStripMenuItem.Click += списокЗаказовToolStripMenuItem_Click; списокЗаказовToolStripMenuItem.Click += списокЗаказовToolStripMenuItem_Click;
// //
// запускРаботToolStripMenuItem
//
запускРаботToolStripMenuItem.Name = апускРаботToolStripMenuItem";
запускРаботToolStripMenuItem.Size = new Size(114, 24);
запускРаботToolStripMenuItem.Text = "Запуск работ";
запускРаботToolStripMenuItem.Click += запускРаботToolStripMenuItem_Click;
//
// DataGridView // DataGridView
// //
DataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; DataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
@ -160,12 +168,12 @@
RefreshButton.UseVisualStyleBackColor = true; RefreshButton.UseVisualStyleBackColor = true;
RefreshButton.Click += RefreshButton_Click; RefreshButton.Click += RefreshButton_Click;
// //
// запускРаботToolStripMenuItem // почтаToolStripMenuItem
// //
запускРаботToolStripMenuItem.Name = "запускРаботToolStripMenuItem"; почтаToolStripMenuItem.Name = "почтаToolStripMenuItem";
запускРаботToolStripMenuItem.Size = new Size(114, 24); почтаToolStripMenuItem.Size = new Size(65, 24);
запускРаботToolStripMenuItem.Text = "Запуск работ"; почтаToolStripMenuItem.Text = "Почта";
запускРаботToolStripMenuItem.Click += запускРаботToolStripMenuItem_Click; почтаToolStripMenuItem.Click += почтаToolStripMenuItem_Click;
// //
// MainForm // MainForm
// //
@ -205,5 +213,6 @@
private ToolStripMenuItem клиентыToolStripMenuItem; private ToolStripMenuItem клиентыToolStripMenuItem;
private ToolStripMenuItem исполнителиToolStripMenuItem; private ToolStripMenuItem исполнителиToolStripMenuItem;
private ToolStripMenuItem запускРаботToolStripMenuItem; private ToolStripMenuItem запускРаботToolStripMenuItem;
private ToolStripMenuItem почтаToolStripMenuItem;
} }
} }

View File

@ -255,5 +255,15 @@ Program.ServiceProvider?.GetService(typeof(ImplementersForm));
MessageBoxButtons.OK, MessageBoxIcon.Information); MessageBoxButtons.OK, MessageBoxIcon.Information);
} }
private void почтаToolStripMenuItem_Click(object sender, EventArgs e)
{
var service =
Program.ServiceProvider?.GetService(typeof(ViewMailForm));
if (service is ViewMailForm form)
{
form.ShowDialog();
}
}
} }
} }

View File

@ -7,6 +7,9 @@ using IceCreamShopDatabaseImplement.Implements;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging; using NLog.Extensions.Logging;
using IceCreamShopBusinessLogic.MailWorker;
using IceCreamShopContracts.BindingModels;
using IceCreamBusinessLogic.BusinessLogics;
namespace IceCreamShop namespace IceCreamShop
{ {
@ -26,7 +29,39 @@ namespace IceCreamShop
var services = new ServiceCollection(); var services = new ServiceCollection();
ConfigureServices(services); ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider(); _serviceProvider = services.BuildServiceProvider();
Application.Run(_serviceProvider.GetRequiredService<MainForm>()); 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, 100000);
}
catch (Exception ex)
{
var logger = _serviceProvider.GetService<ILogger>();
logger?.LogError(ex, "Îøèáêà ðàáîòû ñ ïî÷òîé");
}
Application.Run(_serviceProvider.GetRequiredService<MainForm>());
} }
private static void ConfigureServices(ServiceCollection services) private static void ConfigureServices(ServiceCollection services)
{ {
@ -35,7 +70,8 @@ namespace IceCreamShop
option.SetMinimumLevel(LogLevel.Information); option.SetMinimumLevel(LogLevel.Information);
option.AddNLog("nlog.config"); option.AddNLog("nlog.config");
}); });
services.AddTransient<IComponentStorage, ComponentStorage>(); services.AddSingleton<AbstractMailWorker, MailKitWorker>();
services.AddTransient<IComponentStorage, ComponentStorage>();
services.AddTransient<IOrderStorage, OrderStorage>(); services.AddTransient<IOrderStorage, OrderStorage>();
services.AddTransient<IIceCreamStorage, IceCreamStorage>(); services.AddTransient<IIceCreamStorage, IceCreamStorage>();
services.AddTransient<IComponentLogic, ComponentLogic>(); services.AddTransient<IComponentLogic, ComponentLogic>();
@ -47,8 +83,11 @@ namespace IceCreamShop
services.AddTransient<IClientLogic, ClientLogic>(); services.AddTransient<IClientLogic, ClientLogic>();
services.AddTransient<IClientStorage, ClientStorage>(); services.AddTransient<IClientStorage, ClientStorage>();
services.AddTransient<IWorkProcess, WorkModeling>(); services.AddTransient<IWorkProcess, WorkModeling>();
services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
services.AddTransient<MainForm>(); services.AddTransient<MainForm>();
services.AddTransient<ComponentForm>(); services.AddTransient<ViewMailForm>();
services.AddTransient<ComponentForm>();
services.AddTransient<ComponentsForm>(); services.AddTransient<ComponentsForm>();
services.AddTransient<OrderForm>(); services.AddTransient<OrderForm>();
services.AddTransient<IceCreamForm>(); services.AddTransient<IceCreamForm>();
@ -63,5 +102,8 @@ namespace IceCreamShop
services.AddTransient<AbstractSaveToWord, SaveToWord>(); services.AddTransient<AbstractSaveToWord, SaveToWord>();
services.AddTransient<AbstractSaveToPdf, SaveToPdf>(); services.AddTransient<AbstractSaveToPdf, SaveToPdf>();
} }
}
private static void MailCheck(object obj) =>
ServiceProvider?.GetService<AbstractMailWorker>()?.MailCheck();
}
} }

View File

@ -0,0 +1,62 @@
namespace IceCreamShop
{
partial class ViewMailForm
{
/// <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.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Location = new Point(12, 12);
dataGridView.Name = "dataGridView";
dataGridView.RowHeadersWidth = 51;
dataGridView.RowTemplate.Height = 29;
dataGridView.Size = new Size(776, 426);
dataGridView.TabIndex = 0;
//
// ViewMailForm
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(dataGridView);
Name = "ViewMailForm";
Text = "ViewMailForm";
Load += ViewMailForm_Load;
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView;
}
}

View File

@ -0,0 +1,48 @@
using IceCreamShopContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace IceCreamShop
{
public partial class ViewMailForm : Form
{
private readonly ILogger _logger;
private readonly IMessageInfoLogic _logic;
public ViewMailForm(ILogger<ViewMailForm> logger, IMessageInfoLogic logic)
{
InitializeComponent();
_logger = logger;
_logic = logic;
}
private void ViewMailForm_Load(object sender, EventArgs e)
{
try
{
var list = _logic.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("Загрузка списка писем");
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка загрузки писем");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
}

View File

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

View File

@ -9,6 +9,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IceCreamShopBusinessLogic.BusinessLogic namespace IceCreamShopBusinessLogic.BusinessLogic
@ -109,7 +110,15 @@ namespace IceCreamShopBusinessLogic.BusinessLogic
throw new ArgumentNullException("Нет пароля клиента", throw new ArgumentNullException("Нет пароля клиента",
nameof(model.Password)); nameof(model.Password));
} }
_logger.LogInformation("Client. ClientFIO:{ClientFIO}." + if (!Regex.IsMatch(model.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
{
throw new ArgumentException("Некорретно введен email клиента", nameof(model.Email));
}
if (!Regex.IsMatch(model.Password, @"^(?=.*\d)(?=.*\W)(?=.*[^\d\s]).+$"))
{
throw new ArgumentException("Некорректно введен пароль клиента", nameof(model.Password));
}
_logger.LogInformation("Client. ClientFIO:{ClientFIO}." +
"Email:{ Email}. Password:{ Password}. Id: { Id} ", model.ClientFIO, model.Email, model.Password, model.Id); "Email:{ Email}. Password:{ Password}. Id: { Id} ", model.ClientFIO, model.Email, model.Password, model.Id);
var element = _clientStorage.GetElement(new ClientSearchModel var element = _clientStorage.GetElement(new ClientSearchModel
{ {

View File

@ -0,0 +1,43 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.BusinessLogicsContracts;
using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.StoragesContracts;
using IceCreamShopContracts.ViewModels;
using Microsoft.Extensions.Logging;
namespace IceCreamBusinessLogic.BusinessLogics
{
public class MessageInfoLogic : IMessageInfoLogic
{
private readonly ILogger _logger;
private readonly IMessageInfoStorage _messageInfoStorage;
public MessageInfoLogic(ILogger<MessageInfoLogic> logger, IMessageInfoStorage MessageInfoStorage)
{
_logger = logger;
_messageInfoStorage = MessageInfoStorage;
}
public bool Create(MessageInfoBindingModel model)
{
if (_messageInfoStorage.Insert(model) == null)
{
_logger.LogWarning("Insert operation failed");
return false;
}
return true;
}
public List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model)
{
_logger.LogInformation("ReadList. MessageId:{MessageId}.ClientId:{ClientId} ", model?.MessageId, model?.ClientId);
var list = (model == null) ? _messageInfoStorage.GetFullList() : _messageInfoStorage.GetFilteredList(model);
if (list == null)
{
_logger.LogWarning("ReadList return null list");
return null;
}
_logger.LogInformation("ReadList. Count:{Count}", list.Count);
return list;
}
}
}

View File

@ -1,4 +1,5 @@
using IceCreamShopContracts.BindingModels; using IceCreamShopBusinessLogic.MailWorker;
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.BusinessLogicsContracts; using IceCreamShopContracts.BusinessLogicsContracts;
using IceCreamShopContracts.SearchModels; using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.StoragesContracts; using IceCreamShopContracts.StoragesContracts;
@ -18,13 +19,17 @@ namespace IceCreamShopBusinessLogic.BusinessLogic
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IOrderStorage _orderStorage; private readonly IOrderStorage _orderStorage;
static readonly object locker = new object(); private readonly AbstractMailWorker _mailWorker;
private readonly IClientLogic _clientLogic;
static readonly object locker = new object();
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage) public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, AbstractMailWorker mailWorker, IClientLogic clientLogic)
{ {
_logger = logger; _orderStorage = orderStorage;
_orderStorage = orderStorage; _logger = logger;
} _mailWorker = mailWorker;
_clientLogic = clientLogic;
}
public OrderViewModel? ReadElement(OrderSearchModel model) public OrderViewModel? ReadElement(OrderSearchModel model)
{ {
if (model == null) if (model == null)
@ -61,12 +66,14 @@ namespace IceCreamShopBusinessLogic.BusinessLogic
CheckModel(model); CheckModel(model);
if (model.Status != OrderStatus.Неизвестен) return false; if (model.Status != OrderStatus.Неизвестен) return false;
model.Status = OrderStatus.Принят; model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null) var res = _orderStorage.Insert(model);
if (res == null)
{ {
_logger.LogWarning("Insert operation failed"); _logger.LogWarning("Insert operation failed");
return false; return false;
} }
return true; SendOrderStatusMail(model.ClientId, $"Изменен статус заказа #{res.Id}", $"Заказ #{res.Id} изменен статус на {model.Status}");
return true;
} }
public bool ChangeStatus(OrderBindingModel model, OrderStatus status) public bool ChangeStatus(OrderBindingModel model, OrderStatus status)
@ -87,8 +94,15 @@ namespace IceCreamShopBusinessLogic.BusinessLogic
if (model.Status == OrderStatus.Выдан) model.DateImplement = DateTime.Now; if (model.Status == OrderStatus.Выдан) model.DateImplement = DateTime.Now;
if (element.ImplementerId.HasValue) if (element.ImplementerId.HasValue)
model.ImplementerId = element.ImplementerId; model.ImplementerId = element.ImplementerId;
_orderStorage.Update(model); var result = _orderStorage.Update(model);
return true; if (result == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
SendOrderStatusMail(result.ClientId, $"Изменен статус заказа #{result.Id}", $"Заказ #{model.Id} изменен статус на {result.Status}");
return true;
} }
public bool TakeOrderInWork(OrderBindingModel model) public bool TakeOrderInWork(OrderBindingModel model)
@ -130,5 +144,21 @@ true)
} }
_logger.LogInformation("Order. Sum:{ Cost}. Id: { Id}", model.Sum, model.Id); _logger.LogInformation("Order. Sum:{ Cost}. Id: { Id}", model.Sum, model.Id);
} }
}
private bool SendOrderStatusMail(int clientId, string subject, string text)
{
var client = _clientLogic.ReadElement(new() { Id = clientId });
if (client == null)
{
return false;
}
_mailWorker.MailSendAsync(new()
{
MailAddress = client.Email,
Subject = subject,
Text = text
});
return true;
}
}
} }

View File

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" /> <PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageReference Include="DocumentFormat.OpenXml.Framework" Version="3.0.2" /> <PackageReference Include="DocumentFormat.OpenXml.Framework" Version="3.0.2" />
<PackageReference Include="MailKit" Version="4.5.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" /> <PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,86 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IceCreamShopBusinessLogic.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: {login}, {password}, {clientHost}, { clientPOrt}, { popHost}, { popPort}", _mailLogin, _mailPassword, _smtpClientHost,
_smtpClientPort, _popHost, _popPort);
}
public async void MailSendAsync(MailSendInfoBindingModel info)
{
if (string.IsNullOrEmpty(_mailLogin) ||
string.IsNullOrEmpty(_mailPassword))
{
return;
}
if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0)
{
return;
}
if (string.IsNullOrEmpty(info.MailAddress) ||
string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Text))
{
return;
}
_logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress,
info.Subject);
await SendMailAsync(info);
}
public async void MailCheck()
{
if (string.IsNullOrEmpty(_mailLogin) ||
string.IsNullOrEmpty(_mailPassword))
{
return;
}
if (string.IsNullOrEmpty(_popHost) || _popPort == 0)
{
return;
}
if (_messageInfoLogic == null)
{
return;
}
var list = await ReceiveMailAsync();
_logger.LogDebug("Check Mail: {Count} new mails", list.Count);
foreach (var mail in list)
{
_messageInfoLogic.Create(mail);
}
}
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
protected abstract Task<List<MessageInfoBindingModel>>
ReceiveMailAsync();
}
}

View File

@ -0,0 +1,85 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using System.Text;
using System.Threading.Tasks;
using MailKit.Net.Pop3;
using MailKit.Security;
using System.Net.Mail;
namespace IceCreamShopBusinessLogic.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 (MailKit.Security.AuthenticationException)
{ }
finally
{
client.Disconnect(true);
}
});
return list;
}
}
}

View File

@ -2,6 +2,7 @@
using IceCreamShopContracts.BindingModels; using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.ViewModels; using IceCreamShopContracts.ViewModels;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Diagnostics; using System.Diagnostics;
namespace IceCreamShopClientApp.Controllers namespace IceCreamShopClientApp.Controllers
@ -147,5 +148,16 @@ namespace IceCreamShopClientApp.Controllers
); );
return Math.Round(count * (_iceCream?.Price ?? 1), 2); return Math.Round(count * (_iceCream?.Price ?? 1), 2);
} }
[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

@ -0,0 +1,54 @@
@using IceCreamShopContracts.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

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

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IceCreamShopContracts.BindingModels
{
public class MailConfigBindingModel
{
public string MailLogin { get; set; } = string.Empty;
public string MailPassword { get; set; } = string.Empty;
public string SmtpClientHost { get; set; } = string.Empty;
public int SmtpClientPort { get; set; }
public string PopHost { get; set; } = string.Empty;
public int PopPort { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IceCreamShopContracts.BindingModels
{
public class MailSendInfoBindingModel
{
public string MailAddress { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
public string Text { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,24 @@
using IceCreamShopDataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IceCreamShopContracts.BindingModels
{
public class MessageInfoBindingModel : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.ViewModels;
namespace IceCreamShopContracts.BusinessLogicsContracts
{
public interface IMessageInfoLogic
{
List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model);
bool Create(MessageInfoBindingModel model);
}
}

View File

@ -17,5 +17,6 @@ namespace IceCreamShopContracts.BusinessLogicsContracts
bool TakeOrderInWork(OrderBindingModel model); bool TakeOrderInWork(OrderBindingModel model);
bool FinishOrder(OrderBindingModel model); bool FinishOrder(OrderBindingModel model);
bool DeliveryOrder(OrderBindingModel model); bool DeliveryOrder(OrderBindingModel model);
}
}
} }

View File

@ -0,0 +1,9 @@
namespace IceCreamShopContracts.SearchModels
{
public class MessageInfoSearchModel
{
public int? ClientId { get; set; }
public string? MessageId { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.ViewModels;
namespace IceCreamShopContracts.StoragesContracts
{
public interface IMessageInfoStorage
{
List<MessageInfoViewModel> GetFullList();
List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model);
MessageInfoViewModel? GetElement(MessageInfoSearchModel model);
MessageInfoViewModel? Insert(MessageInfoBindingModel model);
}
}

View File

@ -0,0 +1,24 @@
using IceCreamShopDataModels;
using System.ComponentModel;
namespace IceCreamShopContracts.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; }
[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 IceCreamShopDataModels
{
public interface IMessageInfoModel
{
string MessageId { get; }
int? ClientId { get; }
string SenderName { get; }
DateTime DateDelivery { get; }
string Subject { get; }
string Body { get; }
}
}

View File

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

View File

@ -0,0 +1,52 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.StoragesContracts;
using IceCreamShopContracts.ViewModels;
using IceCreamShopDatabaseImplement.Models;
namespace IceCreamShopDatabaseImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
using var context = new IceCreamShopDataBase();
if (model.MessageId != null)
{
return context.Messages.FirstOrDefault(x => x.MessageId == model.MessageId)?.GetViewModel;
}
return null;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
using var context = new IceCreamShopDataBase();
return context.Messages
.Where(x => x.ClientId == model.ClientId)
.Select(x => x.GetViewModel)
.ToList();
}
public List<MessageInfoViewModel> GetFullList()
{
using var context = new IceCreamShopDataBase();
return context.Messages
.Select(x => x.GetViewModel)
.ToList();
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
using var context = new IceCreamShopDataBase();
var newMessage = MessageInfo.Create(model);
if (newMessage == null || context.Messages.Any(x => x.MessageId.Equals(model.MessageId)))
{
return null;
}
context.Messages.Add(newMessage);
context.SaveChanges();
return newMessage.GetViewModel;
}
}
}

View File

@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace IceCreamShopDatabaseImplement.Migrations namespace IceCreamShopDatabaseImplement.Migrations
{ {
[DbContext(typeof(IceCreamShopDataBase))] [DbContext(typeof(IceCreamShopDataBase))]
[Migration("20240415130513_InitialCreate")] [Migration("20240429125346_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -143,6 +143,36 @@ namespace IceCreamShopDatabaseImplement.Migrations
b.ToTable("Implementers"); b.ToTable("Implementers");
}); });
modelBuilder.Entity("IceCreamShopDatabaseImplement.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("IceCreamShopDatabaseImplement.Models.Order", b => modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.Order", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -205,6 +235,15 @@ namespace IceCreamShopDatabaseImplement.Migrations
b.Navigation("IceCream"); b.Navigation("IceCream");
}); });
modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("IceCreamShopDatabaseImplement.Models.Client", "Client")
.WithMany()
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.Order", b => modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.Order", b =>
{ {
b.HasOne("IceCreamShopDatabaseImplement.Models.Client", "Client") b.HasOne("IceCreamShopDatabaseImplement.Models.Client", "Client")

View File

@ -70,6 +70,27 @@ namespace IceCreamShopDatabaseImplement.Migrations
table.PrimaryKey("PK_Implementers", x => x.Id); table.PrimaryKey("PK_Implementers", 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( migrationBuilder.CreateTable(
name: "IceCreamComponents", name: "IceCreamComponents",
columns: table => new columns: table => new
@ -144,6 +165,11 @@ namespace IceCreamShopDatabaseImplement.Migrations
table: "IceCreamComponents", table: "IceCreamComponents",
column: "IceCreamId"); column: "IceCreamId");
migrationBuilder.CreateIndex(
name: "IX_Messages_ClientId",
table: "Messages",
column: "ClientId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Orders_ClientId", name: "IX_Orders_ClientId",
table: "Orders", table: "Orders",
@ -166,6 +192,9 @@ namespace IceCreamShopDatabaseImplement.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "IceCreamComponents"); name: "IceCreamComponents");
migrationBuilder.DropTable(
name: "Messages");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Orders"); name: "Orders");

View File

@ -140,6 +140,36 @@ namespace IceCreamShopDatabaseImplement.Migrations
b.ToTable("Implementers"); b.ToTable("Implementers");
}); });
modelBuilder.Entity("IceCreamShopDatabaseImplement.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("IceCreamShopDatabaseImplement.Models.Order", b => modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.Order", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -202,6 +232,15 @@ namespace IceCreamShopDatabaseImplement.Migrations
b.Navigation("IceCream"); b.Navigation("IceCream");
}); });
modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("IceCreamShopDatabaseImplement.Models.Client", "Client")
.WithMany()
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.Order", b => modelBuilder.Entity("IceCreamShopDatabaseImplement.Models.Order", b =>
{ {
b.HasOne("IceCreamShopDatabaseImplement.Models.Client", "Client") b.HasOne("IceCreamShopDatabaseImplement.Models.Client", "Client")

View File

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

View File

@ -16,11 +16,15 @@ namespace IceCreamShopFileImplement
private readonly string IceCreamFileName = "IceCream.xml"; private readonly string IceCreamFileName = "IceCream.xml";
private readonly string ClientFileName = "Client.xml"; private readonly string ClientFileName = "Client.xml";
private readonly string ImplementerFileName = "Implementer.xml"; private readonly string ImplementerFileName = "Implementer.xml";
private readonly string MessageInfoFileName = "MessageInfo.xml";
public List<Component> Components { get; private set; } public List<Component> Components { get; private set; }
public List<Order> Orders { get; private set; } public List<Order> Orders { get; private set; }
public List<IceCream> IceCreams { get; private set; } public List<IceCream> IceCreams { get; private set; }
public List<Client> Clients { get; private set; } public List<Client> Clients { get; private set; }
public List<Implementer> Implementers { get; private set; } public List<Implementer> Implementers { get; private set; }
public List<MessageInfo> Messages { get; private set; }
public static DataFileSingleton GetInstance() public static DataFileSingleton GetInstance()
{ {
@ -41,6 +45,8 @@ namespace IceCreamShopFileImplement
"Clients", x => x.GetXElement); "Clients", x => x.GetXElement);
public void SaveImplementers() => SaveData(Implementers, ImplementerFileName, public void SaveImplementers() => SaveData(Implementers, ImplementerFileName,
"Implementers", x => x.GetXElement); "Implementers", x => x.GetXElement);
public void SaveMessages() => SaveData(Orders, ImplementerFileName, "Messages", x => x.GetXElement);
private DataFileSingleton() private DataFileSingleton()
{ {
Components = LoadData(ComponentFileName, "Component", x => Components = LoadData(ComponentFileName, "Component", x =>
@ -53,8 +59,10 @@ namespace IceCreamShopFileImplement
Client.Create(x)!)!; Client.Create(x)!)!;
Implementers = LoadData(ImplementerFileName, "Implementer", x => Implementers = LoadData(ImplementerFileName, "Implementer", x =>
Implementer.Create(x)!)!; Implementer.Create(x)!)!;
Messages = LoadData(MessageInfoFileName, "MessageInfo", x => MessageInfo.Create(x)!)!;
} }
private static List<T>? LoadData<T>(string filename, string xmlNodeName, private static List<T>? LoadData<T>(string filename, string xmlNodeName,
Func<XElement, T> selectFunction) Func<XElement, T> selectFunction)
{ {
if (File.Exists(filename)) if (File.Exists(filename))

View File

@ -0,0 +1,53 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.StoragesContracts;
using IceCreamShopContracts.ViewModels;
using IceCreamShopFileImplement.Models;
namespace IceCreamShopFileImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
private readonly DataFileSingleton _source;
public MessageInfoStorage()
{
_source = DataFileSingleton.GetInstance();
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if (model.MessageId != null)
{
return _source.Messages.FirstOrDefault(x => x.MessageId == model.MessageId)?.GetViewModel;
}
return null;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
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.SaveMessages();
return newMessage.GetViewModel;
}
}
}

View File

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

View File

@ -15,6 +15,8 @@ namespace IceCreamShopListImplement
public List<IceCream> IceCreams { get; set; } public List<IceCream> IceCreams { get; set; }
public List<Client> Clients { get; set; } public List<Client> Clients { get; set; }
public List<Implementer> Implementers { get; set; } public List<Implementer> Implementers { get; set; }
public List<MessageInfo> Messages { get; set; }
private DataListSingleton() private DataListSingleton()
{ {
Components = new List<Component>(); Components = new List<Component>();
@ -22,8 +24,10 @@ namespace IceCreamShopListImplement
IceCreams = new List<IceCream>(); IceCreams = new List<IceCream>();
Clients = new List<Client>(); Clients = new List<Client>();
Implementers = new List<Implementer>(); Implementers = new List<Implementer>();
Messages = new List<MessageInfo>();
} }
public static DataListSingleton GetInstance() public static DataListSingleton GetInstance()
{ {
if (_instance == null) if (_instance == null)
{ {

View File

@ -0,0 +1,61 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.SearchModels;
using IceCreamShopContracts.StoragesContracts;
using IceCreamShopContracts.ViewModels;
using IceCreamShopListImplement.Models;
namespace IceCreamShopListImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
private readonly DataListSingleton _source;
public MessageInfoStorage()
{
_source = DataListSingleton.GetInstance();
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
foreach (var message in _source.Messages)
{
if (model.MessageId != null && model.MessageId.Equals(message.MessageId))
return message.GetViewModel;
}
return null;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
List<MessageInfoViewModel> result = new();
foreach (var item in _source.Messages)
{
if (item.ClientId.HasValue && item.ClientId == model.ClientId)
{
result.Add(item.GetViewModel);
}
}
return result;
}
public List<MessageInfoViewModel> GetFullList()
{
List<MessageInfoViewModel> result = new();
foreach (var item in _source.Messages)
{
result.Add(item.GetViewModel);
}
return result;
}
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,49 @@
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.ViewModels;
using IceCreamShopDataModels;
namespace IceCreamShopListImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
public string MessageId { get; private set; } = string.Empty;
public int? ClientId { get; private set; }
public string SenderName { get; private set; } = string.Empty;
public DateTime DateDelivery { get; private set; } = DateTime.Now;
public string Subject { get; private set; } = string.Empty;
public string Body { get; private set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel model)
{
if (model == null)
{
return null;
}
return new()
{
Body = model.Body,
Subject = model.Subject,
ClientId = model.ClientId,
MessageId = model.MessageId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
};
}
public MessageInfoViewModel GetViewModel => new()
{
Body = Body,
Subject = Subject,
ClientId = ClientId,
MessageId = MessageId,
SenderName = SenderName,
DateDelivery = DateDelivery,
};
}
}

View File

@ -11,11 +11,13 @@ namespace IceCreamShopRestApi.Controllers
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IClientLogic _logic; private readonly IClientLogic _logic;
public ClientController(IClientLogic logic, ILogger<ClientController> private readonly IMessageInfoLogic _mailLogic;
public ClientController(IClientLogic logic, IMessageInfoLogic mailLogic, ILogger<ClientController>
logger) logger)
{ {
_logger = logger; _logger = logger;
_logic = logic; _logic = logic;
_mailLogic = mailLogic;
} }
[HttpGet] [HttpGet]
public ClientViewModel? Login(string login, string password) public ClientViewModel? Login(string login, string password)
@ -34,7 +36,24 @@ namespace IceCreamShopRestApi.Controllers
throw; throw;
} }
} }
[HttpPost] [HttpGet]
public List<MessageInfoViewModel>? GetMessages(int clientId)
{
try
{
return _mailLogic.ReadList(new MessageInfoSearchModel
{
ClientId = clientId
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения писем клиента");
throw;
}
}
[HttpPost]
public void Register(ClientBindingModel model) public void Register(ClientBindingModel model)
{ {
try try

View File

@ -1,4 +1,7 @@
using IceCreamBusinessLogic.BusinessLogics;
using IceCreamShopBusinessLogic.BusinessLogic; using IceCreamShopBusinessLogic.BusinessLogic;
using IceCreamShopBusinessLogic.MailWorker;
using IceCreamShopContracts.BindingModels;
using IceCreamShopContracts.BusinessLogicsContracts; using IceCreamShopContracts.BusinessLogicsContracts;
using IceCreamShopContracts.StoragesContracts; using IceCreamShopContracts.StoragesContracts;
using IceCreamShopDatabaseImplement.Implements; using IceCreamShopDatabaseImplement.Implements;
@ -10,9 +13,17 @@ builder.Logging.AddLog4Net("log4net.config");
builder.Services.AddTransient<IClientStorage, ClientStorage>(); builder.Services.AddTransient<IClientStorage, ClientStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>(); builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<IIceCreamStorage, IceCreamStorage>(); builder.Services.AddTransient<IIceCreamStorage, IceCreamStorage>();
builder.Services.AddTransient<IImplementerStorage, ImplementerStorage>();
builder.Services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>(); builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>(); builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<IIceCreamLogic, IceCreamLogic>(); builder.Services.AddTransient<IIceCreamLogic, IceCreamLogic>();
builder.Services.AddTransient<IImplementerLogic, ImplementerLogic>();
builder.Services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
builder.Services.AddTransient<AbstractMailWorker, MailKitWorker>();
builder.Services.AddControllers(); builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at // Learn more about configuring Swagger/OpenAPI at
https://aka.ms/aspnetcore/swashbuckle https://aka.ms/aspnetcore/swashbuckle
@ -27,6 +38,25 @@ builder.Services.AddSwaggerGen(c =>
}); });
}); });
var app = builder.Build(); 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. // Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {

View File

@ -5,5 +5,13 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"SmtpClientHost": "smtp.gmail.com",
"SmtpClientPort": "587",
"PopHost": "pop.gmail.com",
"PopPort": "995",
"MailLogin": "sasda3183@gmail.com",
"MailPassword": "ozxp vjof uinv fcmj"
} }