ПИбд-21 Кувшинов Тимур сложная лаба 7 #26

Closed
TImourka wants to merge 9 commits from laba7complicated into laba6complicated
46 changed files with 2583 additions and 29 deletions

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.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="PDFsharp-MigraDoc-GDI" Version="1.50.5147" />
</ItemGroup>

View File

@ -4,6 +4,7 @@ using AutomobilePlantContracts.SearchModels;
using AutomobilePlantContracts.StoragesContracts;
using AutomobilePlantContracts.ViewModels;
using Microsoft.Extensions.Logging;
using System.Text.RegularExpressions;
namespace AutomobilePlantBusinessLogic.BusinessLogics
{
@ -98,6 +99,16 @@ namespace AutomobilePlantBusinessLogic.BusinessLogics
{
throw new ArgumentNullException("Нет логина(почты) клиента", nameof(model.Email));
}
if (!Regex.IsMatch(model.Email, @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
+ @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
+ @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$"))
{
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. Id: {Id}, FIO: {fio}, email: {email}", model.Id, model.ClientFIO, model.Email);
var element = _clientStorage.GetElement(new ClientSearchModel
{

View File

@ -0,0 +1,64 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.BusinessLogicsContracts;
using AutomobilePlantContracts.SearchModels;
using AutomobilePlantContracts.StoragesContracts;
using AutomobilePlantContracts.ViewModels;
using Microsoft.Extensions.Logging;
namespace AutomobilePlantBusinessLogic.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}.Page:{Page}.PageSize:{PageSize}", model?.MessageId, model?.ClientId, model?.Page, model?.PageSize);
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;
}
public MessageInfoViewModel? ReadElement(MessageInfoSearchModel model)
{
var message = _messageInfoStorage.GetElement(model);
if (message == null)
{
_logger.LogWarning("Read message operation failed");
return null;
}
return message;
}
public bool Update(MessageInfoBindingModel model)
{
if (_messageInfoStorage.Update(model) == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
return true;
}
}
}

View File

@ -1,4 +1,5 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantBusinessLogic.MailWorker;
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.BusinessLogicsContracts;
using AutomobilePlantContracts.SearchModels;
using AutomobilePlantContracts.StoragesContracts;
@ -21,12 +22,16 @@ namespace AutomobilePlantBusinessLogic.BusinessLogics
private readonly IShopStorage _shopStorage;
private readonly IShopLogic _shopLogic;
private readonly ICarStorage _carStorage;
private readonly AbstractMailWorker _mailWorker;
private readonly IClientLogic _clientLogic;
static readonly object locker = new object();
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IShopLogic shopLogic, ICarStorage carStorage, IShopStorage shopStorage)
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, AbstractMailWorker mailWorker, IClientLogic clientLogic, IShopLogic shopLogic, ICarStorage carStorage, IShopStorage shopStorage)
{
_logger = logger;
_orderStorage = orderStorage;
_mailWorker = mailWorker;
_clientLogic = clientLogic;
_shopLogic = shopLogic;
_carStorage = carStorage;
_shopStorage = shopStorage;
@ -68,12 +73,14 @@ namespace AutomobilePlantBusinessLogic.BusinessLogics
if (model.Status != OrderStatus.Неизвестен)
return false;
model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null)
var result = _orderStorage.Insert(model);
if (result == null)
{
model.Status = OrderStatus.Неизвестен;
_logger.LogWarning("Insert operation failed");
return false;
}
SendOrderStatusMail(result.ClientId, $"A new order has been created. Order number #{result.Id}", $"Order #{result.Id} from {result.DateCreate} for the amount {result.Sum:0.00} {result.Status}");
return true;
}
@ -184,11 +191,13 @@ namespace AutomobilePlantBusinessLogic.BusinessLogics
model.Status = status;
if (model.Status == OrderStatus.Выдан)
model.DateImplement = DateTime.Now;
if (_orderStorage.Update(model) == null)
var result = _orderStorage.Update(model);
if (result == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
SendOrderStatusMail(result.ClientId, $"Status of order #{result.Id} has been changed", $"Order #{result.Id} status has been changed to {result.Status}");
return true;
}
@ -238,5 +247,21 @@ namespace AutomobilePlantBusinessLogic.BusinessLogics
}
_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

@ -0,0 +1,77 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
namespace AutomobilePlantBusinessLogic.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,75 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.BusinessLogicsContracts;
using MailKit.Net.Pop3;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using System.Net.Mail;
using System.Net;
using System.Text;
namespace AutomobilePlantBusinessLogic.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 (MailKit.Security.AuthenticationException)
{ }
finally
{
client.Disconnect(true);
}
});
return list;
}
}
}

View File

@ -134,6 +134,20 @@ namespace AutomobilePlantClientApp.Controllers
var c = APIClient.GetRequest<CarViewModel>($"api/main/getcar?carId={car}");
return count * (c?.Price ?? 1);
}
[HttpGet]
public IActionResult Mails()
{
if (APIClient.Client == null)
{
return Redirect("~/Home/Enter");
}
return View();
}
[HttpPost]
public List<MessageInfoViewModel> LoadMails(int pageNum, int pageSize)
{
return APIClient.GetRequest<List<MessageInfoViewModel>>($"api/client/getmessages?clientId={APIClient.Client.Id}&pageNum={pageNum}&pageSize={pageSize}");
}
}
}

View File

@ -0,0 +1,73 @@
@{
ViewData["Title"] = "Mails";
}
<div class="text-center">
<h1 class="display-4">Mails</h1>
</div>
<div class="text-center">
<table id="mailsTable" class="table">
<thead>
<tr>
<th>
Mail's date'
</th>
<th>
Title
</th>
<th>
Text
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="text-center">
<div>
Page: <input type="number" id="pageNum" value="1" min="1" /> Page Size: <input type="number" id="pageSize" value="2" min="1" />
</div>
</div>
</div>
<script>
$(document).ready(function () {
// Инициализируем значения NumericUpDown с текущими значениями
var pageNum = $('#pageNum').val();
var pageSize = $('#pageSize').val();
// Функция для загрузки данных с сервера
function loadMails(pageNum, pageSize) {
$.ajax({
url: '/Home/LoadMails',
type: 'POST',
data: { pageNum: pageNum, pageSize: pageSize },
success: function (data) {
// Очищаем текущие данные
$('#mailsTable tbody').empty();
// Заполняем таблицу новыми данными
$.each(data, function (index, item) {
var row = $('<tr>');
row.append($('<td>').text(item.dateDelivery));
row.append($('<td>').text(item.subject));
row.append($('<td>').text(item.body));
$('#mailsTable tbody').append(row);
});
},
error: function () {
alert('Error loading mails');
}
});
}
// Загружаем данные при инициализации страницы
loadMails(pageNum, pageSize);
// Обработчик изменений для NumericUpDown
$('#pageNum, #pageSize').change(function () {
pageNum = $('#pageNum').val();
pageSize = $('#pageSize').val();
loadMails(pageNum, pageSize);
});
});
</script>

View File

@ -27,6 +27,9 @@
<li class="nav-item">
<a class="nav-link text-dark" asparea="" asp-controller="Home" asp-action="Privacy">Privacy data</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asparea="" asp-controller="Home" asp-action="Mails">Письма</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asparea="" asp-controller="Home" asp-action="Enter">Enter</a>
</li>

View File

@ -0,0 +1,12 @@
namespace AutomobilePlantContracts.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,9 @@
namespace AutomobilePlantContracts.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,21 @@
using AutomobilePlantDataModels.Models;
namespace AutomobilePlantContracts.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 DateTime DateDelivery { get; set; }
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public bool IsReaded { get; set; }
public string? Reply { get; set; }
}
}

View File

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

View File

@ -0,0 +1,10 @@
namespace AutomobilePlantContracts.SearchModels
{
public class MessageInfoSearchModel
{
public int? ClientId { get; set; }
public string? MessageId { get; set; }
public int? Page { get; set; }
public int? PageSize { get; set; }
}
}

View File

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

View File

@ -0,0 +1,24 @@
using AutomobilePlantDataModels.Models;
using System.ComponentModel;
namespace AutomobilePlantContracts.ViewModels
{
public class MessageInfoViewModel : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
[DisplayName("Sender")]
public string SenderName { get; set; } = string.Empty;
[DisplayName("Delivery Date")]
public DateTime DateDelivery { get; set; }
[DisplayName("Subject")]
public string Subject { get; set; } = string.Empty;
[DisplayName("Body")]
public string Body { get; set; } = string.Empty;
[DisplayName("Readed")]
public bool IsReaded { get; set; }
[DisplayName("Reply")]
public string? Reply { get; set; }
}
}

View File

@ -0,0 +1,14 @@
namespace AutomobilePlantDataModels.Models
{
public interface IMessageInfoModel
{
string MessageId { get; }
int? ClientId { get; }
string SenderName { get; }
DateTime DateDelivery { get; }
string Subject { get; }
string Body { get; }
bool IsReaded { get; }
string? Reply { get; }
}
}

View File

@ -21,5 +21,6 @@ namespace AutomobilePlantDatabaseImplement
public virtual DbSet<ShopCar> ShopCars { 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,69 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.SearchModels;
using AutomobilePlantContracts.StoragesContracts;
using AutomobilePlantContracts.ViewModels;
using AutomobilePlantDatabaseImplement.Models;
namespace AutomobilePlantDatabaseImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
using var context = new AutomobilePlantDatabase();
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 AutomobilePlantDatabase();
var messages = context.Messages
.Where(x => !model.ClientId.HasValue || x.ClientId == model.ClientId)
.Select(x => x.GetViewModel)
.ToList();
if (!model.Page.HasValue || !model.PageSize.HasValue)
{
return messages.ToList();
}
return messages.Skip((model.Page.Value - 1) * model.PageSize.Value).Take(model.PageSize.Value).ToList();
}
public List<MessageInfoViewModel> GetFullList()
{
using var context = new AutomobilePlantDatabase();
return context.Messages
.Select(x => x.GetViewModel)
.ToList();
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
using var context = new AutomobilePlantDatabase();
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;
}
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
using var context = new AutomobilePlantDatabase();
var message = context.Messages.FirstOrDefault(x => x.MessageId.Equals(model.MessageId));
if (message != null)
{
message.Update(model);
context.SaveChanges();
}
return message?.GetViewModel;
}
}
}

View File

@ -0,0 +1,298 @@
// <auto-generated />
using System;
using AutomobilePlantDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AutomobilePlantDatabaseImplement.Migrations
{
[DbContext(typeof(AutomobilePlantDatabase))]
[Migration("20240504192703_MbINeedIt7Laba")]
partial class MbINeedIt7Laba
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.16")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Car", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("CarName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Cars");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.CarComponent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("CarId")
.HasColumnType("int");
b.Property<int>("ComponentId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("CarId");
b.HasIndex("ComponentId");
b.ToTable("CarComponents");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Clients");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Component", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ComponentName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Cost")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Components");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Implementer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ImplementerFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("Qualification")
.HasColumnType("int");
b.Property<int>("WorkExperience")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Implementers");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.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("AutomobilePlantDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("CarId")
.HasColumnType("int");
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<int?>("ImplementerId")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<double>("Sum")
.HasColumnType("float");
b.HasKey("Id");
b.HasIndex("CarId");
b.HasIndex("ClientId");
b.HasIndex("ImplementerId");
b.ToTable("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.CarComponent", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Car", "Car")
.WithMany("Components")
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Component", "Component")
.WithMany("CarComponents")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Car");
b.Navigation("Component");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Order", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Car", "Car")
.WithMany("Orders")
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Client", "Client")
.WithMany("Orders")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Implementer", "Implementer")
.WithMany("Orders")
.HasForeignKey("ImplementerId");
b.Navigation("Car");
b.Navigation("Client");
b.Navigation("Implementer");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Car", b =>
{
b.Navigation("Components");
b.Navigation("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Component", b =>
{
b.Navigation("CarComponents");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Implementer", b =>
{
b.Navigation("Orders");
});
#pragma warning restore 612, 618
}
}
}

View File

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

View File

@ -0,0 +1,381 @@
// <auto-generated />
using System;
using AutomobilePlantDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AutomobilePlantDatabaseImplement.Migrations
{
[DbContext(typeof(AutomobilePlantDatabase))]
[Migration("20240505173052_MbINeedItLC7")]
partial class MbINeedItLC7
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.16")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Car", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("CarName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Cars");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.CarComponent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("CarId")
.HasColumnType("int");
b.Property<int>("ComponentId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("CarId");
b.HasIndex("ComponentId");
b.ToTable("CarComponents");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Clients");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Component", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ComponentName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Cost")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Components");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Implementer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ImplementerFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("Qualification")
.HasColumnType("int");
b.Property<int>("WorkExperience")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Implementers");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.MessageInfo", b =>
{
b.Property<string>("MessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("Body")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("DateDelivery")
.HasColumnType("datetime2");
b.Property<bool>("IsReaded")
.HasColumnType("bit");
b.Property<string>("Reply")
.HasColumnType("nvarchar(max)");
b.Property<string>("SenderName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Subject")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.ToTable("Messages");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("CarId")
.HasColumnType("int");
b.Property<int>("ClientId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<int?>("ImplementerId")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<double>("Sum")
.HasColumnType("float");
b.HasKey("Id");
b.HasIndex("CarId");
b.HasIndex("ClientId");
b.HasIndex("ImplementerId");
b.ToTable("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("MaxCountCars")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("OpeningDate")
.HasColumnType("datetime2");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.ShopCar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("CarId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("CarId");
b.HasIndex("ShopId");
b.ToTable("ShopCars");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.CarComponent", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Car", "Car")
.WithMany("Components")
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Component", "Component")
.WithMany("CarComponents")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Car");
b.Navigation("Component");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Order", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Car", "Car")
.WithMany("Orders")
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Client", "Client")
.WithMany("Orders")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Implementer", "Implementer")
.WithMany("Orders")
.HasForeignKey("ImplementerId");
b.Navigation("Car");
b.Navigation("Client");
b.Navigation("Implementer");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.ShopCar", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Car", "Car")
.WithMany()
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AutomobilePlantDatabaseImplement.Models.Shop", "Shop")
.WithMany("Cars")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Car");
b.Navigation("Shop");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Car", b =>
{
b.Navigation("Components");
b.Navigation("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Component", b =>
{
b.Navigation("CarComponents");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Implementer", b =>
{
b.Navigation("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Cars");
});
#pragma warning restore 612, 618
}
}
}

View File

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

View File

@ -140,6 +140,42 @@ namespace AutomobilePlantDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.MessageInfo", b =>
{
b.Property<string>("MessageId")
.HasColumnType("nvarchar(450)");
b.Property<string>("Body")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("ClientId")
.HasColumnType("int");
b.Property<DateTime>("DateDelivery")
.HasColumnType("datetime2");
b.Property<bool>("IsReaded")
.HasColumnType("bit");
b.Property<string>("Reply")
.HasColumnType("nvarchar(max)");
b.Property<string>("SenderName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Subject")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.ToTable("Messages");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -255,6 +291,15 @@ namespace AutomobilePlantDatabaseImplement.Migrations
b.Navigation("Component");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Client", "Client")
.WithMany("Messages")
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Order", b =>
{
b.HasOne("AutomobilePlantDatabaseImplement.Models.Car", "Car")
@ -308,6 +353,8 @@ namespace AutomobilePlantDatabaseImplement.Migrations
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Client", b =>
{
b.Navigation("Messages");
b.Navigation("Orders");
});
@ -316,15 +363,15 @@ namespace AutomobilePlantDatabaseImplement.Migrations
b.Navigation("CarComponents");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Cars");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Implementer", b =>
{
b.Navigation("Orders");
});
modelBuilder.Entity("AutomobilePlantDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Cars");
});
#pragma warning restore 612, 618
}
}

View File

@ -22,6 +22,9 @@ namespace AutomobilePlantDatabaseImplement.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,68 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.ViewModels;
using AutomobilePlantDataModels.Models;
using System.ComponentModel.DataAnnotations;
namespace AutomobilePlantDatabaseImplement.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 bool IsReaded { get; private set; }
public string? Reply { get; private set; }
public virtual 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,
IsReaded = model.IsReaded,
Reply = model.Reply
};
}
public void Update(MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
Reply = model.Reply;
IsReaded = model.IsReaded;
}
public MessageInfoViewModel GetViewModel => new()
{
Body = Body,
Subject = Subject,
ClientId = ClientId,
MessageId = MessageId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Reply = Reply,
IsReaded = IsReaded,
};
}
}

View File

@ -1,9 +1,4 @@
using AutomobilePlantFileImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace AutomobilePlantFileImplement
@ -17,12 +12,14 @@ namespace AutomobilePlantFileImplement
private readonly string ShopFileName = "Shop.xml";
private readonly string ClientFileName = "Client.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<Car> Cars { get; private set; }
public List<Shop> Shops { 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()
{
if (instance == null)
@ -37,6 +34,7 @@ namespace AutomobilePlantFileImplement
public void SaveShops() => SaveData(Shops, ShopFileName, "Shops", x => x.GetXElement);
public void SaveClients() => SaveData(Clients, ClientFileName, "Clients", x => x.GetXElement);
public void SaveImplementers() => SaveData(Orders, ImplementerFileName, "Implementers", x => x.GetXElement);
public void SaveMessages() => SaveData(Orders, ImplementerFileName, "Messages", x => x.GetXElement);
private DataFileSingleton()
{
Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!;
@ -45,6 +43,7 @@ namespace AutomobilePlantFileImplement
Shops = LoadData(ShopFileName, "Shop", x => Shop.Create(x)!)!;
Clients = LoadData(ClientFileName, "Client", x => Client.Create(x)!)!;
Implementers = LoadData(ImplementerFileName, "Impleneter", 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,69 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.SearchModels;
using AutomobilePlantContracts.StoragesContracts;
using AutomobilePlantContracts.ViewModels;
using AutomobilePlantFileImplement.Models;
namespace AutomobilePlantFileImplement.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)
{
var messages = _source.Messages
.Where(x => !model.ClientId.HasValue || x.ClientId == model.ClientId)
.Select(x => x.GetViewModel)
.ToList();
if (!model.Page.HasValue || !model.PageSize.HasValue)
{
return messages.ToList();
}
return messages.Skip((model.Page.Value - 1) * model.PageSize.Value).Take(model.PageSize.Value).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;
}
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
var message = _source.Messages.FirstOrDefault(x => x.MessageId.Equals(model.MessageId));
if (message != null)
{
message.Update(model);
_source.SaveMessages();
}
return message?.GetViewModel;
}
}
}

View File

@ -0,0 +1,97 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.ViewModels;
using AutomobilePlantDataModels.Models;
using System.Xml.Linq;
namespace AutomobilePlantFileImplement.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 bool IsReaded { get; private set; }
public string? Reply { 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,
Reply = model.Reply,
IsReaded = model.IsReaded,
};
}
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),
Reply = element.Attribute("Reply")!.Value,
IsReaded = Convert.ToBoolean(element.Attribute("IsReaded")!.Value),
};
}
public void Update(MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
Reply = model.Reply;
IsReaded = model.IsReaded;
}
public MessageInfoViewModel GetViewModel => new()
{
Body = Body,
Subject = Subject,
ClientId = ClientId,
MessageId = MessageId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Reply = Reply,
IsReaded = IsReaded,
};
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),
new XAttribute("Reply", Reply),
new XAttribute("HasRead", IsReaded)
);
}
}

View File

@ -1,9 +1,4 @@
using AutomobilePlantListImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AutomobilePlantListImplement
{
@ -16,6 +11,7 @@ namespace AutomobilePlantListImplement
public List<Shop> Shops { 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>();
@ -24,6 +20,7 @@ namespace AutomobilePlantListImplement
Shops = new List<Shop>();
Clients = new List<Client>();
Implementers = new List<Implementer>();
Messages = new List<MessageInfo>();
}
public static DataListSingleton GetInstance()
{

View File

@ -0,0 +1,76 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.SearchModels;
using AutomobilePlantContracts.StoragesContracts;
using AutomobilePlantContracts.ViewModels;
using AutomobilePlantListImplement.Models;
namespace AutomobilePlantListImplement.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 (!model.ClientId.HasValue || item.ClientId == model.ClientId)
{
result.Add(item.GetViewModel);
}
}
if (!model.Page.HasValue || !model.PageSize.HasValue)
{
return result;
}
return result.Skip((model.Page.Value - 1) * model.PageSize.Value).Take(model.PageSize.Value).ToList();
}
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;
}
public MessageInfoViewModel? Update(MessageInfoBindingModel model)
{
foreach (var message in _source.Messages)
{
if (message.MessageId.Equals(model.MessageId))
{
message.Update(model);
return message.GetViewModel;
}
}
return null;
}
}
}

View File

@ -0,0 +1,66 @@
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.ViewModels;
using AutomobilePlantDataModels.Models;
namespace AutomobilePlantListImplement.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 bool IsReaded { get; private set; }
public string? Reply { 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,
Reply = model.Reply,
IsReaded = model.IsReaded,
};
}
public void Update(MessageInfoBindingModel model)
{
if (model == null)
{
return;
}
Reply = model.Reply;
IsReaded = model.IsReaded;
}
public MessageInfoViewModel GetViewModel => new()
{
Body = Body,
Subject = Subject,
ClientId = ClientId,
MessageId = MessageId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Reply = Reply,
IsReaded = IsReaded,
};
}
}

View File

@ -12,10 +12,12 @@ namespace AutomobilePlantRestApi.Controllers
{
private readonly ILogger _logger;
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]
public ClientViewModel? Login(string login, string password)
@ -60,5 +62,23 @@ namespace AutomobilePlantRestApi.Controllers
throw;
}
}
[HttpGet]
public List<MessageInfoViewModel>? GetMessages(int clientId, int pageNum, int pageSize)
{
try
{
return _mailLogic.ReadList(new MessageInfoSearchModel
{
ClientId = clientId,
Page = pageNum,
PageSize = pageSize
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения писем клиента");
throw;
}
}
}
}

View File

@ -1,4 +1,6 @@
using AutomobilePlantBusinessLogic.BusinessLogics;
using AutomobilePlantBusinessLogic.MailWorker;
using AutomobilePlantContracts.BindingModels;
using AutomobilePlantContracts.BusinessLogicsContracts;
using AutomobilePlantContracts.StoragesContracts;
using AutomobilePlantDatabaseImplement.Implements;
@ -14,11 +16,14 @@ builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<ICarStorage, CarStorage>();
builder.Services.AddTransient<IShopStorage, ShopStorage>();
builder.Services.AddTransient<IImplementerStorage, ImplementerStorage>();
builder.Services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<ICarLogic, CarLogic>();
builder.Services.AddTransient<IShopLogic, ShopLogic>();
builder.Services.AddTransient<IImplementerLogic, ImplementerLogic>();
builder.Services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
builder.Services.AddSingleton<AbstractMailWorker, MailKitWorker>();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@ -34,6 +39,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,13 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"SmtpClientHost": "smtp.gmail.com",
"SmtpClientPort": "587",
"PopHost": "pop.gmail.com",
"PopPort": "995",
"MailLogin": "bes1s1uden1@gmail.com",
"MailPassword": "wxwq srug vuhi dwoq"
}

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="bes1s1uden1@gmail.com" />
<add key="MailPassword" value="wxwq srug vuhi dwoq" />
</appSettings>
</configuration>

View File

@ -27,6 +27,9 @@
</ItemGroup>
<ItemGroup>
<None Update="App.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="nlog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@ -0,0 +1,195 @@
namespace AutomobilePlantView
{
partial class FormMail
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
textBoxHead = new TextBox();
textBoxBody = new TextBox();
labelHead = new Label();
labelBody = new Label();
labelFrom = new Label();
labelHeadReply = new Label();
labelBoryReply = new Label();
labelMessage = new Label();
labelHeadMessage = new Label();
label1 = new Label();
buttonCancel = new Button();
buttonSave = new Button();
SuspendLayout();
//
// textBoxHead
//
textBoxHead.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
textBoxHead.Location = new Point(85, 256);
textBoxHead.Name = "textBoxHead";
textBoxHead.Size = new Size(703, 23);
textBoxHead.TabIndex = 0;
//
// textBoxBody
//
textBoxBody.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
textBoxBody.Location = new Point(85, 285);
textBoxBody.Multiline = true;
textBoxBody.Name = "textBoxBody";
textBoxBody.Size = new Size(703, 153);
textBoxBody.TabIndex = 1;
//
// labelHead
//
labelHead.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
labelHead.Location = new Point(103, 32);
labelHead.Name = "labelHead";
labelHead.Size = new Size(685, 61);
labelHead.TabIndex = 2;
labelHead.Text = "Head";
//
// labelBody
//
labelBody.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
labelBody.Location = new Point(103, 93);
labelBody.Name = "labelBody";
labelBody.Size = new Size(685, 160);
labelBody.TabIndex = 3;
labelBody.Text = "Body";
//
// labelFrom
//
labelFrom.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
labelFrom.Location = new Point(103, 9);
labelFrom.Name = "labelFrom";
labelFrom.Size = new Size(685, 23);
labelFrom.TabIndex = 4;
labelFrom.Text = "From";
//
// labelHeadReply
//
labelHeadReply.AutoSize = true;
labelHeadReply.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
labelHeadReply.Location = new Point(12, 259);
labelHeadReply.Name = "labelHeadReply";
labelHeadReply.Size = new Size(67, 15);
labelHeadReply.TabIndex = 5;
labelHeadReply.Text = "Head reply:";
//
// labelBoryReply
//
labelBoryReply.AutoSize = true;
labelBoryReply.Location = new Point(12, 288);
labelBoryReply.Name = "labelBoryReply";
labelBoryReply.Size = new Size(66, 15);
labelBoryReply.TabIndex = 6;
labelBoryReply.Text = "Body reply:";
//
// labelMessage
//
labelMessage.AutoSize = true;
labelMessage.Location = new Point(12, 93);
labelMessage.Name = "labelMessage";
labelMessage.Size = new Size(86, 15);
labelMessage.TabIndex = 8;
labelMessage.Text = "Body message:";
//
// labelHeadMessage
//
labelHeadMessage.AutoSize = true;
labelHeadMessage.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
labelHeadMessage.Location = new Point(12, 32);
labelHeadMessage.Name = "labelHeadMessage";
labelHeadMessage.Size = new Size(87, 15);
labelHeadMessage.TabIndex = 7;
labelHeadMessage.Text = "Head message:";
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(12, 9);
label1.Name = "label1";
label1.Size = new Size(85, 15);
label1.TabIndex = 9;
label1.Text = "Message from:";
//
// buttonCancel
//
buttonCancel.Location = new Point(713, 449);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(75, 23);
buttonCancel.TabIndex = 10;
buttonCancel.Text = "Cancel";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// buttonSave
//
buttonSave.Location = new Point(632, 449);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(75, 23);
buttonSave.TabIndex = 11;
buttonSave.Text = "Save";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// FormMail
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 484);
Controls.Add(buttonSave);
Controls.Add(buttonCancel);
Controls.Add(label1);
Controls.Add(labelMessage);
Controls.Add(labelHeadMessage);
Controls.Add(labelBoryReply);
Controls.Add(labelHeadReply);
Controls.Add(labelFrom);
Controls.Add(labelBody);
Controls.Add(labelHead);
Controls.Add(textBoxBody);
Controls.Add(textBoxHead);
Name = "FormMail";
Text = "Mail";
Load += FormMail_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private TextBox textBoxHead;
private TextBox textBoxBody;
private Label labelHead;
private Label labelBody;
private Label labelFrom;
private Label labelHeadReply;
private Label labelBoryReply;
private Label labelMessage;
private Label labelHeadMessage;
private Label label1;
private Button buttonCancel;
private Button buttonSave;
}
}

View File

@ -0,0 +1,79 @@
using AutomobilePlantBusinessLogic.MailWorker;
using AutomobilePlantContracts.BusinessLogicsContracts;
using AutomobilePlantContracts.ViewModels;
using Microsoft.Extensions.Logging;
namespace AutomobilePlantView
{
public partial class FormMail : Form
{
private readonly ILogger _logger;
private readonly AbstractMailWorker _mailWorker;
private readonly IMessageInfoLogic _logic;
private MessageInfoViewModel _message;
public string MessageId { get; set; } = string.Empty;
public FormMail(ILogger<FormMail> logger, AbstractMailWorker mailWorker, IMessageInfoLogic logic)
{
InitializeComponent();
_logger = logger;
_mailWorker = mailWorker;
_logic = logic;
}
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void buttonSave_Click(object sender, EventArgs e)
{
_mailWorker.MailSendAsync(new()
{
MailAddress = _message.SenderName,
Subject = textBoxHead.Text,
Text = textBoxBody.Text,
});
_logic.Update(new()
{
MessageId = MessageId,
Reply = textBoxBody.Text,
IsReaded = true,
});
MessageBox.Show("Успешно отправлен ответ", "Отправлен ответ", MessageBoxButtons.OK);
DialogResult = DialogResult.OK;
Close();
}
private void FormMail_Load(object sender, EventArgs e)
{
try
{
_message = _logic.ReadElement(new() { MessageId = MessageId });
if (_message == null) throw new ArgumentNullException("Письма с таким Id не существует");
_logic.Update(new()
{
MessageId = MessageId,
Reply = _message.Reply,
IsReaded = true,
});
labelHead.Text = _message.Subject;
labelBody.Text = _message.Body;
labelFrom.Text = $"From: {_message.SenderName}";
if (_message.IsReaded is false)
{
_logic.Update(new() { MessageId = MessageId, IsReaded = true, Reply = _message.Reply });
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения собщения");
MessageBox.Show(ex.Message, "Eror", 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

@ -0,0 +1,140 @@
namespace AutomobilePlantView
{
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();
panel1 = new Panel();
numericUpDownPageSize = new NumericUpDown();
labelPageSize = new Label();
numericUpDownPage = new NumericUpDown();
labelPage = new Label();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)numericUpDownPageSize).BeginInit();
((System.ComponentModel.ISupportInitialize)numericUpDownPage).BeginInit();
SuspendLayout();
//
// dataGridView
//
dataGridView.AllowUserToAddRows = false;
dataGridView.AllowUserToDeleteRows = false;
dataGridView.AllowUserToResizeColumns = false;
dataGridView.AllowUserToResizeRows = false;
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(800, 450);
dataGridView.TabIndex = 0;
dataGridView.RowHeaderMouseDoubleClick += dataGridView_RowHeaderMouseDoubleClick;
//
// panel1
//
panel1.Controls.Add(numericUpDownPageSize);
panel1.Controls.Add(labelPageSize);
panel1.Controls.Add(numericUpDownPage);
panel1.Controls.Add(labelPage);
panel1.Dock = DockStyle.Bottom;
panel1.Location = new Point(0, 395);
panel1.Name = "panel1";
panel1.Size = new Size(800, 55);
panel1.TabIndex = 1;
//
// numericUpDownPageSize
//
numericUpDownPageSize.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
numericUpDownPageSize.Location = new Point(229, 14);
numericUpDownPageSize.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
numericUpDownPageSize.Name = "numericUpDownPageSize";
numericUpDownPageSize.Size = new Size(67, 29);
numericUpDownPageSize.TabIndex = 6;
numericUpDownPageSize.Value = new decimal(new int[] { 2, 0, 0, 0 });
numericUpDownPageSize.ValueChanged += numericUpDownPageSize_ValueChanged;
//
// labelPageSize
//
labelPageSize.AutoSize = true;
labelPageSize.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
labelPageSize.Location = new Point(137, 16);
labelPageSize.Name = "labelPageSize";
labelPageSize.Padding = new Padding(10, 0, 0, 0);
labelPageSize.Size = new Size(86, 21);
labelPageSize.TabIndex = 5;
labelPageSize.Text = "Page size:";
//
// numericUpDownPage
//
numericUpDownPage.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
numericUpDownPage.Location = new Point(64, 14);
numericUpDownPage.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
numericUpDownPage.Name = "numericUpDownPage";
numericUpDownPage.Size = new Size(67, 29);
numericUpDownPage.TabIndex = 4;
numericUpDownPage.Value = new decimal(new int[] { 1, 0, 0, 0 });
numericUpDownPage.ValueChanged += numericUpDownPage_ValueChanged;
//
// labelPage
//
labelPage.AutoSize = true;
labelPage.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
labelPage.Location = new Point(12, 16);
labelPage.Name = "labelPage";
labelPage.Size = new Size(46, 21);
labelPage.TabIndex = 1;
labelPage.Text = "Page:";
//
// FormMails
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(panel1);
Controls.Add(dataGridView);
Name = "FormMails";
Text = "Mails";
Load += FormMails_Load;
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
panel1.ResumeLayout(false);
panel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)numericUpDownPageSize).EndInit();
((System.ComponentModel.ISupportInitialize)numericUpDownPage).EndInit();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView;
private Panel panel1;
private Label labelPage;
private NumericUpDown numericUpDownPage;
private NumericUpDown numericUpDownPageSize;
private Label labelPageSize;
}
}

View File

@ -0,0 +1,73 @@
using AutomobilePlantContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
namespace AutomobilePlantView
{
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;
}
void LoadData()
{
try
{
var list = _logic.ReadList(new()
{
Page = ((int)numericUpDownPage.Value),
PageSize = ((int)numericUpDownPageSize.Value),
});
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);
}
}
private void FormMails_Load(object sender, EventArgs e)
{
LoadData();
}
private void numericUpDownPage_ValueChanged(object sender, EventArgs e)
{
LoadData();
}
private void numericUpDownPageSize_ValueChanged(object sender, EventArgs e)
{
LoadData();
}
private void dataGridView_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (dataGridView.SelectedRows.Count == 1)
{
var service = Program.ServiceProvider?.GetService(typeof(FormMail));
if (service is FormMail form)
{
form.MessageId = (string)(dataGridView.SelectedRows[0].Cells["MessageId"].Value);
form.ShowDialog();
LoadData();
}
}
}
}
}

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

@ -41,6 +41,7 @@
carsListToolStripMenuItem = new ToolStripMenuItem();
componentsByCarsToolStripMenuItem = new ToolStripMenuItem();
ordersListToolStripMenuItem = new ToolStripMenuItem();
startWorkingsToolStripMenuItem = new ToolStripMenuItem();
dataGridView = new DataGridView();
buttonCreateOrder = new Button();
buttonIssuedOrder = new Button();
@ -50,6 +51,7 @@
listOdOrdersByDatesToolStripMenuItem = new ToolStripMenuItem();
clientsToolStripMenuItem = new ToolStripMenuItem();
startWorkingsToolStripMenuItem = new ToolStripMenuItem();
mailsToolStripMenuItem = new ToolStripMenuItem();
menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
@ -65,7 +67,7 @@
//
// toolStripMenuItemCatalogs
//
toolStripMenuItemCatalogs.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItemComponents, toolStripMenuItemCars, clientsToolStripMenuItem, shopsToolStripMenuItem, shopsSupplyToolStripMenuItem, sellCarsToolStripMenuItem, implementersToolStripMenuItem });
toolStripMenuItemCatalogs.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItemComponents, toolStripMenuItemCars, clientsToolStripMenuItem, shopsToolStripMenuItem, shopsSupplyToolStripMenuItem, sellCarsToolStripMenuItem, implementersToolStripMenuItem, mailsToolStripMenuItem });
toolStripMenuItemCatalogs.Name = "toolStripMenuItemCatalogs";
toolStripMenuItemCatalogs.Size = new Size(65, 20);
toolStripMenuItemCatalogs.Text = "Catalogs";
@ -73,7 +75,6 @@
// toolStripMenuItemComponents
//
toolStripMenuItemComponents.Name = "toolStripMenuItemComponents";
toolStripMenuItemComponents.Size = new Size(147, 22);
toolStripMenuItemComponents.Size = new Size(180, 22);
toolStripMenuItemComponents.Text = "Components";
toolStripMenuItemComponents.Click += ComponentsToolStripMenuItem_Click;
@ -148,6 +149,13 @@
ordersListToolStripMenuItem.Text = "Orders' list";
ordersListToolStripMenuItem.Click += ordersListToolStripMenuItem_Click;
//
// startWorkingsToolStripMenuItem
//
startWorkingsToolStripMenuItem.Name = "startWorkingsToolStripMenuItem";
startWorkingsToolStripMenuItem.Size = new Size(94, 20);
startWorkingsToolStripMenuItem.Text = "Start workings";
startWorkingsToolStripMenuItem.Click += startWorkingsToolStripMenuItem_Click;
//
// dataGridView
//
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
@ -210,11 +218,12 @@
//
// clientsToolStripMenuItem
// startWorkingsToolStripMenuItem
// mailsToolStripMenuItem
//
startWorkingsToolStripMenuItem.Name = "startWorkingsToolStripMenuItem";
startWorkingsToolStripMenuItem.Size = new Size(94, 20);
startWorkingsToolStripMenuItem.Text = "Start workings";
startWorkingsToolStripMenuItem.Click += startWorkingsToolStripMenuItem_Click;
mailsToolStripMenuItem.Name = "mailsToolStripMenuItem";
mailsToolStripMenuItem.Size = new Size(180, 22);
mailsToolStripMenuItem.Text = "mails";
mailsToolStripMenuItem.Click += mailsToolStripMenuItem_Click;
//
// FormMain
//
@ -259,5 +268,6 @@
private ToolStripMenuItem clientsToolStripMenuItem;
private ToolStripMenuItem implementersToolStripMenuItem;
private ToolStripMenuItem startWorkingsToolStripMenuItem;
private ToolStripMenuItem mailsToolStripMenuItem;
}
}

View File

@ -98,6 +98,15 @@ namespace AutomobilePlantView
}
}
private void mailsToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormMails));
if (service is FormMails form)
{
form.ShowDialog();
}
}
private void carsListToolStripMenuItem_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog { Filter = "docx|*.docx" };

View File

@ -1,4 +1,4 @@
using AutomobilePlantBusinessLogic.BusinessLogics;
using AutomobilePlantBusinessLogic.BusinessLogics;
using AutomobilePlantBusinessLogic.OfficePackage.Implements;
using AutomobilePlantBusinessLogic.OfficePackage;
using AutomobilePlantContracts.BusinessLogicsContracts;
@ -7,6 +7,8 @@ using AutomobilePlantDatabaseImplement.Implements;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using AutomobilePlantBusinessLogic.MailWorker;
using AutomobilePlantContracts.BindingModels;
namespace AutomobilePlantView
{
@ -26,8 +28,31 @@ namespace AutomobilePlantView
var services = new ServiceCollection();
ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider();
try
{
var mailSender = _serviceProvider.GetService<AbstractMailWorker>();
mailSender?.MailConfig(new MailConfigBindingModel
{
MailLogin = System.Configuration.ConfigurationManager.AppSettings["MailLogin"] ?? string.Empty,
MailPassword = System.Configuration.ConfigurationManager.AppSettings["MailPassword"] ?? string.Empty,
SmtpClientHost = System.Configuration.ConfigurationManager.AppSettings["SmtpClientHost"] ?? string.Empty,
SmtpClientPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["SmtpClientPort"]),
PopHost = System.Configuration.ConfigurationManager.AppSettings["PopHost"] ?? string.Empty,
PopPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["PopPort"])
});
// создаем таймер
var timer = new System.Threading.Timer(new TimerCallback(MailCheck!), null, 0, 100000);
}
catch (Exception ex)
{
var logger = _serviceProvider.GetService<ILogger>();
logger?.LogError(ex, "Ошибка работы с почтой");
}
Application.Run(_serviceProvider.GetRequiredService<FormMain>());
}
private static void MailCheck(object obj) => ServiceProvider?.GetService<AbstractMailWorker>()?.MailCheck();
private static void ConfigureServices(ServiceCollection services)
{
services.AddLogging(option =>
@ -40,18 +65,21 @@ namespace AutomobilePlantView
services.AddTransient<ICarStorage, CarStorage>();
services.AddTransient<IClientStorage, ClientStorage>();
services.AddTransient<IImplementerStorage, ImplementerStorage>();
services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
services.AddTransient<IComponentLogic, ComponentLogic>();
services.AddTransient<IOrderLogic, OrderLogic>();
services.AddTransient<ICarLogic, CarLogic>();
services.AddTransient<IReportLogic, ReportLogic>();
services.AddTransient<IClientLogic, ClientLogic>();
services.AddTransient<IImplementerLogic, ImplementerLogic>();
services.AddTransient<IMessageInfoLogic, MessageInfoLogic>();
services.AddTransient<AbstractSaveToWord, SaveToWord>();
services.AddTransient<AbstractSaveToExcel, SaveToExcel>();
services.AddTransient<AbstractSaveToPdf, SaveToPdf>();
services.AddTransient<IShopStorage, ShopStorage>();
services.AddTransient<IShopLogic, ShopLogic>();
services.AddTransient<IWorkProcess, WorkModeling>();
services.AddSingleton<AbstractMailWorker, MailKitWorker>();
services.AddTransient<FormMain>();
services.AddTransient<FormComponent>();
services.AddTransient<FormComponents>();
@ -70,6 +98,8 @@ namespace AutomobilePlantView
services.AddTransient<FormClients>();
services.AddTransient<FormImplementers>();
services.AddTransient<FormImplementer>();
}
services.AddTransient<FormMails>();
services.AddTransient<FormMail>();
}
}
}