7 Commits

Author SHA1 Message Date
1db325c1cd fix 2023-04-30 13:44:29 +04:00
70779878ca fix 2023-04-29 17:50:26 +04:00
c2bb2a8669 fix 2023-04-29 16:57:41 +04:00
09a53bf0ca fix 2023-04-29 15:26:46 +04:00
43b1b104b9 fix 2023-04-29 15:10:19 +04:00
005c8c0b3e вроде всё 2023-04-21 16:16:14 +04:00
d0e74d8b3a дурка 2023-04-21 15:19:48 +04:00
47 changed files with 1414 additions and 169 deletions

View File

@@ -143,5 +143,15 @@ namespace FoodOrdersClientApp.Controllers
var prod = APIClient.GetRequest<DishViewModel>($"api/main/getdish?dishId={dish}");
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

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

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

View File

@@ -0,0 +1,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="nonomusay@gmail.com" />
<add key="MailPassword" value="tfpa mttm puph zusk" />
</appSettings>
</configuration>

View File

@@ -38,6 +38,9 @@
</ItemGroup>
<ItemGroup>
<None Update="App.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="ReportOrders.rdlc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@@ -0,0 +1,64 @@
using DocumentFormat.OpenXml.Wordprocessing;
namespace FoodOrdersView
{
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.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Dock = DockStyle.Fill;
dataGridView.Location = new Point(0, 0);
dataGridView.Name = "dataGridView";
dataGridView.RowTemplate.Height = 25;
dataGridView.Size = new Size(803, 450);
dataGridView.TabIndex = 0;
//
// FormMails
//
AutoScaleDimensions = new SizeF(7F, 15F);
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;
}
}

View File

@@ -0,0 +1,40 @@
using Microsoft.Extensions.Logging;
using FoodOrdersContracts.BusinessLogicsContracts;
namespace FoodOrdersView
{
public partial class FormMails : Form
{
private readonly ILogger _logger;
private readonly IMessageInfoLogic _logic;
public FormMails(ILogger<FormMails> logger, IMessageInfoLogic logic)
{
InitializeComponent();
_logger = logger;
_logic = logic;
}
private void FormMails_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

@@ -28,179 +28,176 @@
/// </summary>
private void InitializeComponent()
{
this.menuStrip = new System.Windows.Forms.MenuStrip();
this.справочникиToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.БлюдаToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.наборблюдToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ClientToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.отчётыToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.componentsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.componentDishesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ordersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.buttonUpdate = new System.Windows.Forms.Button();
this.buttonSetToFinish = new System.Windows.Forms.Button();
this.buttonCreateOrder = new System.Windows.Forms.Button();
this.dataGridView = new System.Windows.Forms.DataGridView();
this.DoWorkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.исполнителиToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
this.SuspendLayout();
menuStrip = new MenuStrip();
справочникиToolStripMenuItem = new ToolStripMenuItem();
БлюдаToolStripMenuItem = new ToolStripMenuItem();
наборблюдToolStripMenuItem = new ToolStripMenuItem();
ClientToolStripMenuItem = new ToolStripMenuItem();
исполнителиToolStripMenuItem = new ToolStripMenuItem();
отчётыToolStripMenuItem = new ToolStripMenuItem();
componentsToolStripMenuItem = new ToolStripMenuItem();
componentDishesToolStripMenuItem = new ToolStripMenuItem();
ordersToolStripMenuItem = new ToolStripMenuItem();
DoWorkToolStripMenuItem = new ToolStripMenuItem();
buttonUpdate = new Button();
buttonSetToFinish = new Button();
buttonCreateOrder = new Button();
dataGridView = new DataGridView();
письмаToolStripMenuItem = new ToolStripMenuItem();
menuStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
//
// menuStrip
//
this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.справочникиToolStripMenuItem,
this.отчётыToolStripMenuItem,
this.DoWorkToolStripMenuItem});
this.menuStrip.Location = new System.Drawing.Point(0, 0);
this.menuStrip.Name = "menuStrip";
this.menuStrip.Size = new System.Drawing.Size(975, 24);
this.menuStrip.TabIndex = 0;
this.menuStrip.Text = "menuStrip1";
menuStrip.Items.AddRange(new ToolStripItem[] { справочникиToolStripMenuItem, отчётыToolStripMenuItem, DoWorkToolStripMenuItem, письмаToolStripMenuItem });
menuStrip.Location = new Point(0, 0);
menuStrip.Name = "menuStrip";
menuStrip.Size = new Size(975, 24);
menuStrip.TabIndex = 0;
menuStrip.Text = "menuStrip1";
//
// справочникиToolStripMenuItem
//
this.справочникиToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.БлюдаToolStripMenuItem,
this.наборблюдToolStripMenuItem,
this.ClientToolStripMenuItem,
this.исполнителиToolStripMenuItem});
this.справочникиToolStripMenuItem.Name = "справочникиToolStripMenuItem";
this.справочникиToolStripMenuItem.Size = new System.Drawing.Size(94, 20);
this.справочникиToolStripMenuItem.Text = "Справочники";
справочникиToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { БлюдаToolStripMenuItem, наборблюдToolStripMenuItem, ClientToolStripMenuItem, исполнителиToolStripMenuItem });
справочникиToolStripMenuItem.Name = "справочникиToolStripMenuItem";
справочникиToolStripMenuItem.Size = new Size(94, 20);
справочникиToolStripMenuItem.Text = "Справочники";
//
// БлюдаToolStripMenuItem
//
this.БлюдаToolStripMenuItem.Name = "БлюдаToolStripMenuItem";
this.БлюдаToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.БлюдаToolStripMenuItem.Text = "Блюда";
this.БлюдаToolStripMenuItem.Click += new System.EventHandler(this.ComponentsToolStripMenuItem_Click);
БлюдаToolStripMenuItem.Name = "БлюдаToolStripMenuItem";
БлюдаToolStripMenuItem.Size = new Size(149, 22);
БлюдаToolStripMenuItem.Text = "Блюда";
БлюдаToolStripMenuItem.Click += ComponentsToolStripMenuItem_Click;
//
// наборблюдToolStripMenuItem
//
this.наборблюдToolStripMenuItem.Name = аборблюдToolStripMenuItem";
this.наборблюдToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.наборблюдToolStripMenuItem.Text = "Набор блюд";
this.наборблюдToolStripMenuItem.Click += new System.EventHandler(this.DishToolStripMenuItem_Click);
наборблюдToolStripMenuItem.Name = аборблюдToolStripMenuItem";
наборблюдToolStripMenuItem.Size = new Size(149, 22);
наборблюдToolStripMenuItem.Text = "Набор блюд";
наборблюдToolStripMenuItem.Click += DishToolStripMenuItem_Click;
//
// ClientToolStripMenuItem
//
this.ClientToolStripMenuItem.Name = "ClientToolStripMenuItem";
this.ClientToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.ClientToolStripMenuItem.Text = "Клиент";
this.ClientToolStripMenuItem.Click += new System.EventHandler(this.ClientToolStripMenuItem_Click);
//
// отчётыToolStripMenuItem
//
this.отчётыToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.componentsToolStripMenuItem,
this.componentDishesToolStripMenuItem,
this.ordersToolStripMenuItem});
this.отчётыToolStripMenuItem.Name = "отчётыToolStripMenuItem";
this.отчётыToolStripMenuItem.Size = new System.Drawing.Size(60, 20);
this.отчётыToolStripMenuItem.Text = "Отчёты";
//
// componentsToolStripMenuItem
//
this.componentsToolStripMenuItem.Name = "componentsToolStripMenuItem";
this.componentsToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.componentsToolStripMenuItem.Text = "Список Компонентов";
this.componentsToolStripMenuItem.Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// componentDishesToolStripMenuItem
//
this.componentDishesToolStripMenuItem.Name = "componentDishesToolStripMenuItem";
this.componentDishesToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.componentDishesToolStripMenuItem.Text = "Компоненты по блюдам";
this.componentDishesToolStripMenuItem.Click += new System.EventHandler(this.ComponentDishesToolStripMenuItem_Click);
//
// ordersToolStripMenuItem
//
this.ordersToolStripMenuItem.Name = "ordersToolStripMenuItem";
this.ordersToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.ordersToolStripMenuItem.Text = "Список заказов";
this.ordersToolStripMenuItem.Click += new System.EventHandler(this.OrdersToolStripMenuItem_Click);
//
// buttonUpdate
//
this.buttonUpdate.Location = new System.Drawing.Point(780, 230);
this.buttonUpdate.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.buttonUpdate.Name = "buttonUpdate";
this.buttonUpdate.Size = new System.Drawing.Size(170, 58);
this.buttonUpdate.TabIndex = 12;
this.buttonUpdate.Text = "Обновить";
this.buttonUpdate.UseVisualStyleBackColor = true;
this.buttonUpdate.Click += new System.EventHandler(this.ButtonRef_Click);
//
// buttonSetToFinish
//
this.buttonSetToFinish.Location = new System.Drawing.Point(780, 149);
this.buttonSetToFinish.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.buttonSetToFinish.Name = "buttonSetToFinish";
this.buttonSetToFinish.Size = new System.Drawing.Size(170, 58);
this.buttonSetToFinish.TabIndex = 11;
this.buttonSetToFinish.Text = "Заказ выдан";
this.buttonSetToFinish.UseVisualStyleBackColor = true;
this.buttonSetToFinish.Click += new System.EventHandler(this.ButtonIssuedOrder_Click);
//
// buttonCreateOrder
//
this.buttonCreateOrder.Location = new System.Drawing.Point(780, 66);
this.buttonCreateOrder.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.buttonCreateOrder.Name = "buttonCreateOrder";
this.buttonCreateOrder.Size = new System.Drawing.Size(170, 58);
this.buttonCreateOrder.TabIndex = 8;
this.buttonCreateOrder.Text = "Создать заказ";
this.buttonCreateOrder.UseVisualStyleBackColor = true;
this.buttonCreateOrder.Click += new System.EventHandler(this.ButtonCreateOrder_Click);
//
// dataGridView
//
this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView.Dock = System.Windows.Forms.DockStyle.Left;
this.dataGridView.Location = new System.Drawing.Point(0, 24);
this.dataGridView.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.dataGridView.Name = "dataGridView";
this.dataGridView.RowHeadersWidth = 51;
this.dataGridView.RowTemplate.Height = 29;
this.dataGridView.Size = new System.Drawing.Size(755, 426);
this.dataGridView.TabIndex = 7;
//
// DoWorkToolStripMenuItem
//
this.DoWorkToolStripMenuItem.Name = "DoWorkToolStripMenuItem";
this.DoWorkToolStripMenuItem.Size = new System.Drawing.Size(92, 20);
this.DoWorkToolStripMenuItem.Text = "Запуск работ";
this.DoWorkToolStripMenuItem.Click += new System.EventHandler(this.DoWorkToolStripMenuItem_Click);
ClientToolStripMenuItem.Name = "ClientToolStripMenuItem";
ClientToolStripMenuItem.Size = new Size(149, 22);
ClientToolStripMenuItem.Text = "Клиент";
ClientToolStripMenuItem.Click += ClientToolStripMenuItem_Click;
//
// исполнителиToolStripMenuItem
//
this.исполнителиToolStripMenuItem.Name = сполнителиToolStripMenuItem";
this.исполнителиToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.исполнителиToolStripMenuItem.Text = "Исполнители";
this.исполнителиToolStripMenuItem.Click += new System.EventHandler(this.ImplementersToolStripMenuItem_Click);
исполнителиToolStripMenuItem.Name = сполнителиToolStripMenuItem";
исполнителиToolStripMenuItem.Size = new Size(149, 22);
исполнителиToolStripMenuItem.Text = "Исполнители";
исполнителиToolStripMenuItem.Click += ImplementersToolStripMenuItem_Click;
//
// отчётыToolStripMenuItem
//
отчётыToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { componentsToolStripMenuItem, componentDishesToolStripMenuItem, ordersToolStripMenuItem });
отчётыToolStripMenuItem.Name = "отчётыToolStripMenuItem";
отчётыToolStripMenuItem.Size = new Size(60, 20);
отчётыToolStripMenuItem.Text = "Отчёты";
//
// componentsToolStripMenuItem
//
componentsToolStripMenuItem.Name = "componentsToolStripMenuItem";
componentsToolStripMenuItem.Size = new Size(210, 22);
componentsToolStripMenuItem.Text = "Список Компонентов";
componentsToolStripMenuItem.Click += ToolStripMenuItem_Click;
//
// componentDishesToolStripMenuItem
//
componentDishesToolStripMenuItem.Name = "componentDishesToolStripMenuItem";
componentDishesToolStripMenuItem.Size = new Size(210, 22);
componentDishesToolStripMenuItem.Text = "Компоненты по блюдам";
componentDishesToolStripMenuItem.Click += ComponentDishesToolStripMenuItem_Click;
//
// ordersToolStripMenuItem
//
ordersToolStripMenuItem.Name = "ordersToolStripMenuItem";
ordersToolStripMenuItem.Size = new Size(210, 22);
ordersToolStripMenuItem.Text = "Список заказов";
ordersToolStripMenuItem.Click += OrdersToolStripMenuItem_Click;
//
// DoWorkToolStripMenuItem
//
DoWorkToolStripMenuItem.Name = "DoWorkToolStripMenuItem";
DoWorkToolStripMenuItem.Size = new Size(92, 20);
DoWorkToolStripMenuItem.Text = "Запуск работ";
DoWorkToolStripMenuItem.Click += DoWorkToolStripMenuItem_Click;
//
// buttonUpdate
//
buttonUpdate.Location = new Point(780, 230);
buttonUpdate.Margin = new Padding(3, 2, 3, 2);
buttonUpdate.Name = "buttonUpdate";
buttonUpdate.Size = new Size(170, 58);
buttonUpdate.TabIndex = 12;
buttonUpdate.Text = "Обновить";
buttonUpdate.UseVisualStyleBackColor = true;
buttonUpdate.Click += ButtonRef_Click;
//
// buttonSetToFinish
//
buttonSetToFinish.Location = new Point(780, 149);
buttonSetToFinish.Margin = new Padding(3, 2, 3, 2);
buttonSetToFinish.Name = "buttonSetToFinish";
buttonSetToFinish.Size = new Size(170, 58);
buttonSetToFinish.TabIndex = 11;
buttonSetToFinish.Text = "Заказ выдан";
buttonSetToFinish.UseVisualStyleBackColor = true;
buttonSetToFinish.Click += ButtonIssuedOrder_Click;
//
// buttonCreateOrder
//
buttonCreateOrder.Location = new Point(780, 66);
buttonCreateOrder.Margin = new Padding(3, 2, 3, 2);
buttonCreateOrder.Name = "buttonCreateOrder";
buttonCreateOrder.Size = new Size(170, 58);
buttonCreateOrder.TabIndex = 8;
buttonCreateOrder.Text = "Создать заказ";
buttonCreateOrder.UseVisualStyleBackColor = true;
buttonCreateOrder.Click += ButtonCreateOrder_Click;
//
// dataGridView
//
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Dock = DockStyle.Left;
dataGridView.Location = new Point(0, 24);
dataGridView.Margin = new Padding(3, 2, 3, 2);
dataGridView.Name = "dataGridView";
dataGridView.RowHeadersWidth = 51;
dataGridView.RowTemplate.Height = 29;
dataGridView.Size = new Size(755, 426);
dataGridView.TabIndex = 7;
//
// письмаToolStripMenuItem
//
письмаToolStripMenuItem.Name = "письмаToolStripMenuItem";
письмаToolStripMenuItem.Size = new Size(62, 20);
письмаToolStripMenuItem.Text = "Письма";
письмаToolStripMenuItem.Click += MailsToolStripMenuItem_Click;
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(975, 450);
this.Controls.Add(this.buttonUpdate);
this.Controls.Add(this.buttonSetToFinish);
this.Controls.Add(this.buttonCreateOrder);
this.Controls.Add(this.dataGridView);
this.Controls.Add(this.menuStrip);
this.MainMenuStrip = this.menuStrip;
this.Name = "FormMain";
this.Text = "Набор блюд";
this.Load += new System.EventHandler(this.FormMain_Load);
this.menuStrip.ResumeLayout(false);
this.menuStrip.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(975, 450);
Controls.Add(buttonUpdate);
Controls.Add(buttonSetToFinish);
Controls.Add(buttonCreateOrder);
Controls.Add(dataGridView);
Controls.Add(menuStrip);
MainMenuStrip = menuStrip;
Name = "FormMain";
Text = "Набор блюд";
Load += FormMain_Load;
menuStrip.ResumeLayout(false);
menuStrip.PerformLayout();
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
@@ -220,5 +217,6 @@
private ToolStripMenuItem ClientToolStripMenuItem;
private ToolStripMenuItem исполнителиToolStripMenuItem;
private ToolStripMenuItem DoWorkToolStripMenuItem;
private ToolStripMenuItem письмаToolStripMenuItem;
}
}

View File

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

View File

@@ -7,9 +7,9 @@ using FoodOrdersDatabaseImplement.Implements;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using FoodOrdersView;
using FoodOrdersBusinessLogic.BusinessLogics;
using FoodOrdersContracts.BusinessLogicsContracts;
using FoodOrdersBusinessLogic.MailWorker;
using FoodOrdersContracts.BindingModels;
using FoodOrdersDatabaseImplement;
namespace FoodOrdersView
{
@@ -31,6 +31,28 @@ namespace FoodOrdersView
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"])
});
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var timer = new System.Threading.Timer(new TimerCallback(MailCheck!), null, 0, 100000);
}
catch (Exception ex)
{
var logger = _serviceProvider.GetService<ILogger>();
logger?.LogError(ex, "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
}
Application.Run(_serviceProvider.GetRequiredService<FormMain>());
}
@@ -46,6 +68,7 @@ namespace FoodOrdersView
services.AddTransient<IDishStorage, DishStorage>();
services.AddTransient<IClientStorage, ClientStorage>();
services.AddTransient<IImplementerStorage, ImplementerStorage>();
services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
services.AddTransient<IComponentLogic, ComponentLogic>();
services.AddTransient<IOrderLogic, OrderLogic>();
@@ -53,7 +76,10 @@ namespace FoodOrdersView
services.AddTransient<IReportLogic, ReportLogic>();
services.AddTransient<IClientLogic, ClientLogic>();
services.AddTransient<IImplementerLogic, ImplementerLogic>();
services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
services.AddTransient<IWorkProcess, WorkModeling>();
services.AddSingleton<AbstractMailWorker, MailKitWorker>();
services.AddTransient<AbstractSaveToExcel, SaveToExcel>();
services.AddTransient<AbstractSaveToWord, SaveToWord>();
@@ -71,6 +97,9 @@ namespace FoodOrdersView
services.AddTransient<FormReportOrders>();
services.AddTransient<FormViewImplementers>();
services.AddTransient<FormImplementer>();
services.AddTransient<FormMails>();
}
private static void MailCheck(object obj) => ServiceProvider?.GetService<AbstractMailWorker>()?.MailCheck();
}
}

View File

@@ -4,6 +4,7 @@ using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.StoragesContracts;
using FoodOrdersContracts.ViewModels;
using Microsoft.Extensions.Logging;
using System.Text.RegularExpressions;
namespace FoodOrdersBusinessLogic.BusinessLogics
{
@@ -102,7 +103,10 @@ namespace FoodOrdersBusinessLogic.BusinessLogics
{
throw new ArgumentNullException("Нет пароля клиента", nameof(model.Password));
}
if (!Regex.IsMatch(model.Password, @"^^((\w+\d+\W+)|(\w+\W+\d+)|(\d+\w+\W+)|(\d+\W+\w+)|(\W+\w+\d+)|(\W+\d+\w+))[\w\d\W]*$", RegexOptions.IgnoreCase) && (model.Password.Length < 10 || model.Password.Length > 50))
{
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);
var element = _clienttStorage.GetElement(new ClientSearchModel
{

View File

@@ -0,0 +1,43 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.BusinessLogicsContracts;
using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.StoragesContracts;
using FoodOrdersContracts.ViewModels;
using Microsoft.Extensions.Logging;
namespace FoodOrdersBusinessLogic.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. ClientId:{ClientId}", 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,6 @@
using FoodOrdersContracts.BindingModels;
using DocumentFormat.OpenXml.EMMA;
using FoodOrdersBusinessLogic.MailWorker;
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.BusinessLogicsContracts;
using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.StoragesContracts;
@@ -12,10 +14,14 @@ namespace FoodOrdersBusinessLogic.BusinessLogics
{
private readonly ILogger _logger;
private readonly IOrderStorage _orderStorage;
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage)
private readonly AbstractMailWorker _mailWorker;
private readonly IClientLogic _clientLogic;
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, AbstractMailWorker mailWorker, IClientLogic clientLogic)
{
_logger = logger;
_orderStorage = orderStorage;
_mailWorker = mailWorker;
_clientLogic = clientLogic;
}
public OrderViewModel? ReadElement(OrderSearchModel model)
@@ -57,12 +63,14 @@ namespace FoodOrdersBusinessLogic.BusinessLogics
return false;
}
model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null)
var order = _orderStorage.Insert(model);
if (order == null)
{
model.Status = OrderStatus.Неизвестен;
_logger.LogWarning("Insert operation failed");
return false;
}
SendToClient(order.ClientId, $"Заказ №{order.Id}", $"Заказ №{order.Id} от {order.DateCreate} на сумму {order.Sum} принят.");
return true;
}
@@ -136,11 +144,30 @@ namespace FoodOrdersBusinessLogic.BusinessLogics
model.DateImplement = viewModel.DateImplement;
}
CheckModel(model, false);
if (_orderStorage.Update(model) == null)
var order = _orderStorage.Update(model);
if (order == null)
{
_logger.LogWarning("Change status operation failed");
return false;
}
SendToClient(order.ClientId, $"Заказ №{order.Id}", $"У заказа №{order.Id} изменен статус на {order.Status}.");
return true;
}
private bool SendToClient(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

@@ -75,6 +75,7 @@ namespace FoodOrdersBusinessLogic.BusinessLogics
_orderLogic.FinishOrder(new OrderBindingModel
{
Id = order.Id,
ImplementerId = implementer.Id
});
// отдыхаем
Thread.Sleep(implementer.Qualification * _rnd.Next(10, 100));

View File

@@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.19.0" />
<PackageReference Include="MailKit" Version="4.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />

View File

@@ -0,0 +1,98 @@
using FoodOrdersBusinessLogic.BusinessLogics;
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using System.Net.Mail;
namespace FoodOrdersBusinessLogic.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 IClientLogic _clientLogic;
private readonly ILogger _logger;
public AbstractMailWorker(ILogger<AbstractMailWorker> logger, IMessageInfoLogic messageInfoLogic, IClientLogic clientLogic)
{
_logger = logger;
_messageInfoLogic = messageInfoLogic;
_clientLogic = clientLogic;
}
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)
{
mail.ClientId = _clientLogic.ReadElement(new() { Email = mail.SenderName })?.Id;
_messageInfoLogic.Create(mail);
}
}
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
protected abstract Task<List<MessageInfoBindingModel>> ReceiveMailAsync();
}
}

View File

@@ -0,0 +1,79 @@
using FoodOrdersBusinessLogic.BusinessLogics;
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.BusinessLogicsContracts;
using MailKit.Net.Pop3;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using System.Net;
using System.Net.Mail;
using System.Text;
namespace FoodOrdersBusinessLogic.MailWorker
{
public class MailKitWorker : AbstractMailWorker
{
public MailKitWorker(ILogger<MailKitWorker> logger, IMessageInfoLogic messageInfoLogic, IClientLogic clientLogic) : base(logger, messageInfoLogic, clientLogic) { }
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,17 @@
namespace FoodOrdersContracts.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,11 @@
namespace FoodOrdersContracts.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,19 @@
using FoodOrdersDataModels.Models;
namespace FoodOrdersContracts.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 FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.ViewModels;
namespace FoodOrdersContracts.BusinessLogicsContracts
{
public interface IMessageInfoLogic
{
List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model);
bool Create(MessageInfoBindingModel model);
}
}

View File

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

View File

@@ -0,0 +1,17 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.ViewModels;
namespace FoodOrdersContracts.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 FoodOrdersDataModels.Models;
using System.ComponentModel;
namespace FoodOrdersContracts.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,17 @@
namespace FoodOrdersDataModels.Models
{
public interface IMessageInfoModel
{
string MessageId { get; }
int? ClientId { get; }
string SenderName { get; }
DateTime DateDelivery { get; }
string Subject { get; }
string Body { get; }
}
}

View File

@@ -9,7 +9,7 @@ namespace FoodOrdersDatabaseImplement
{
if (optionsBuilder.IsConfigured == false)
{
optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-SINQU55\SQLEXPRESS;Initial Catalog=FoodOrdersDatabase1;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True");
optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-SINQU55\SQLEXPRESS;Initial Catalog=FoodOrdersDatabase3;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True");
}
base.OnConfiguring(optionsBuilder);
}
@@ -23,6 +23,9 @@ namespace FoodOrdersDatabaseImplement
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

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

View File

@@ -12,8 +12,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace FoodOrdersDatabaseImplement.Migrations
{
[DbContext(typeof(FoodOrdersDatabase))]
[Migration("20230409213338_6b")]
partial class _6b
[Migration("20230429112639_B7")]
partial class B7
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -143,6 +143,36 @@ namespace FoodOrdersDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("FoodOrdersDatabaseImplement.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("FoodOrdersDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@@ -205,6 +235,15 @@ namespace FoodOrdersDatabaseImplement.Migrations
b.Navigation("Dish");
});
modelBuilder.Entity("FoodOrdersDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("FoodOrdersDatabaseImplement.Models.Client", "Client")
.WithMany()
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("FoodOrdersDatabaseImplement.Models.Order", b =>
{
b.HasOne("FoodOrdersDatabaseImplement.Models.Client", "Client")

View File

@@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace FoodOrdersDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class _6b : Migration
public partial class B7 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
@@ -70,6 +70,27 @@ namespace FoodOrdersDatabaseImplement.Migrations
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(
name: "DishComponents",
columns: table => new
@@ -144,6 +165,11 @@ namespace FoodOrdersDatabaseImplement.Migrations
table: "DishComponents",
column: "DishId");
migrationBuilder.CreateIndex(
name: "IX_Messages_ClientId",
table: "Messages",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_Orders_ClientId",
table: "Orders",
@@ -166,6 +192,9 @@ namespace FoodOrdersDatabaseImplement.Migrations
migrationBuilder.DropTable(
name: "DishComponents");
migrationBuilder.DropTable(
name: "Messages");
migrationBuilder.DropTable(
name: "Orders");

View File

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

View File

@@ -23,6 +23,9 @@ namespace FoodOrdersDatabaseImplement.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,49 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.ViewModels;
using FoodOrdersDataModels.Models;
using System.ComponentModel.DataAnnotations;
namespace FoodOrdersDatabaseImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
[Key]
public string MessageId { get; private set; } = string.Empty;
public int? ClientId { get; private set; }
[Required]
public string SenderName { get; private set; } = string.Empty;
[Required]
public DateTime DateDelivery { get; private set; }
[Required]
public string Subject { get; private set; } = string.Empty;
[Required]
public string Body { get; private 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,
Body = model.Body,
Subject = model.Subject,
DateDelivery = model.DateDelivery,
};
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
Body = Body,
Subject = Subject,
DateDelivery = DateDelivery,
};
}
}

View File

@@ -10,11 +10,13 @@ namespace FoodOrdersFileImplement
private readonly string DishFileName = "Dish.xml";
private readonly string ClientFileName = "Clients.xml";
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<Dish> Dishes { 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()
{
@@ -29,6 +31,7 @@ namespace FoodOrdersFileImplement
public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement);
public void SaveClients() => SaveData(Clients, ClientFileName, "Clients", x => x.GetXElement);
public void SaveImplementer() => SaveData(Implementers, ImplementerFileName, "Implementer", x => x.GetXElement);
public void SaveMessages() => SaveData(Orders, ImplementerFileName, "Messages", x => x.GetXElement);
private DataFileSingleton()
{
Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!;
@@ -36,6 +39,7 @@ namespace FoodOrdersFileImplement
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,53 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.StoragesContracts;
using FoodOrdersContracts.ViewModels;
using FoodOrdersFileImplement.Models;
namespace FoodOrdersFileImplement.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,87 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.ViewModels;
using FoodOrdersDataModels.Models;
using System.Runtime.Serialization;
using System.Xml.Linq;
namespace FoodOrdersFileImplement.Models
{
// Update в этой сущности не нужен, поскольку в логике мы не изменяем никакие поля после создания письма
[DataContract]
public class MessageInfo : IMessageInfoModel
{
[DataMember]
public string MessageId { get; private set; } = string.Empty;
[DataMember]
public int? ClientId { get; private set; }
[DataMember]
public string SenderName { get; private set; } = string.Empty;
[DataMember]
public DateTime DateDelivery { get; private set; } = DateTime.Now;
[DataMember]
public string Subject { get; private set; } = string.Empty;
[DataMember]
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)
);
public int Id => throw new NotImplementedException();
}
}

View File

@@ -1,4 +1,5 @@
using FoodOrdersListImplement.Models;
using static System.Formats.Asn1.AsnWriter;
namespace FoodOrdersListImplement
{
@@ -10,6 +11,7 @@ namespace FoodOrdersListImplement
public List<Dish> Dishes { 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 +19,7 @@ namespace FoodOrdersListImplement
Dishes = new List<Dish>();
Clients = new List<Client>();
Implementers = new List<Implementer>();
Messages = new List<MessageInfo>();
}
public static DataListSingleton GetInstance()
{

View File

@@ -0,0 +1,61 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.SearchModels;
using FoodOrdersContracts.StoragesContracts;
using FoodOrdersContracts.ViewModels;
using FoodOrdersListImplement.Models;
namespace FoodOrdersListImplement.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,52 @@
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.ViewModels;
using FoodOrdersDataModels.Models;
namespace FoodOrdersListImplement.Models
{
// Update в этой сущности не нужен, поскольку в логике мы не изменяем никакие поля после создания письма
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,
};
public int Id => throw new NotImplementedException();
}
}

View File

@@ -14,10 +14,13 @@ namespace FoodOrdersRestApi.Controllers
private readonly IClientLogic _logic;
public ClientController(IClientLogic logic, ILogger<ClientController> logger)
private readonly IMessageInfoLogic _mailLogic;
public ClientController(IClientLogic logic, IMessageInfoLogic mailLogic, ILogger<ClientController> logger)
{
_logger = logger;
_logic = logic;
_mailLogic = mailLogic;
}
[HttpGet]
@@ -65,5 +68,22 @@ namespace FoodOrdersRestApi.Controllers
throw;
}
}
[HttpGet]
public List<MessageInfoViewModel>? GetMessages(int clientId)
{
try
{
return _mailLogic.ReadList(new MessageInfoSearchModel
{
ClientId = clientId
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения писем клиента");
throw;
}
}
}
}

View File

@@ -1,4 +1,6 @@
using FoodOrdersBusinessLogic.BusinessLogics;
using FoodOrdersBusinessLogic.MailWorker;
using FoodOrdersContracts.BindingModels;
using FoodOrdersContracts.BusinessLogicsContracts;
using FoodOrdersContracts.StoragesContracts;
using FoodOrdersDatabaseImplement.Implements;
@@ -11,12 +13,18 @@ builder.Logging.AddLog4Net("log4net.config");
// Add services to the container.
builder.Services.AddTransient<IClientStorage, ClientStorage>();
builder.Services.AddTransient<IImplementerStorage, ImplementerStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<IDishStorage, DishStorage>();
builder.Services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IImplementerLogic, ImplementerLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<IDishLogic, DishLogic>();
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
@@ -28,6 +36,17 @@ builder.Services.AddSwaggerGen(c =>
var app = builder.Build();
var mailSender = app.Services.GetService<AbstractMailWorker>();
mailSender?.MailConfig(new MailConfigBindingModel
{
MailLogin = builder.Configuration?.GetSection("MailLogin")?.Value?.ToString() ?? string.Empty,
MailPassword = builder.Configuration?.GetSection("MailPassword")?.Value?.ToString() ?? string.Empty,
SmtpClientHost = builder.Configuration?.GetSection("SmtpClientHost")?.Value?.ToString() ?? string.Empty,
SmtpClientPort = Convert.ToInt32(builder.Configuration?.GetSection("SmtpClientPort")?.Value?.ToString()),
PopHost = builder.Configuration?.GetSection("PopHost")?.Value?.ToString() ?? string.Empty,
PopPort = Convert.ToInt32(builder.Configuration?.GetSection("PopPort")?.Value?.ToString())
});
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{

View File

@@ -5,5 +5,12 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"SmtpClientHost": "smtp.gmail.com",
"SmtpClientPort": "587",
"PopHost": "pop.gmail.com",
"PopPort": "995",
"MailLogin": "nonomusay@gmail.com",
"MailPassword": "tfpa mttm puph zusk"
}