PIbd-21 Yakovlev M.G. lab work 7 #10

Closed
YakovlevMaxim wants to merge 7 commits from Lab7_Base into Lab6_Base
43 changed files with 1306 additions and 22 deletions

View File

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace CarRepairShopBusinessLogic.BusinessLogics
@ -97,7 +98,11 @@ namespace CarRepairShopBusinessLogic.BusinessLogics
{
throw new ArgumentNullException("Нет ФИО клиента", nameof(model.ClientFIO));
}
if (string.IsNullOrEmpty(model.Password))
if (string.IsNullOrEmpty(model.Email) || !Regex.IsMatch(model.Email, @"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$", RegexOptions.IgnoreCase))
{
throw new ArgumentNullException("Нет почты клиента", nameof(model.Email));
}
if (string.IsNullOrEmpty(model.Password) || !Regex.IsMatch(model.Password, @"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$", RegexOptions.IgnoreCase))
{
throw new ArgumentNullException("Нет пароля клиента", nameof(model.ClientFIO));
}

View File

@ -0,0 +1,51 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.BusinessLogicsContracts;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.StoragesContracts;
using CarRepairShopContracts.ViewModels;
using CarRepairShopDataModels.Enums;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopBusinessLogic.BusinessLogics
{
public class MessageInfoLogic : IMessageInfoLogic
{
private readonly ILogger _logger;
private readonly IMessageInfoStorage _storage;
public MessageInfoLogic(ILogger<MessageInfoLogic> logger, IMessageInfoStorage storage)
{
_logger = logger;
_storage = storage;
}
public List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model)
{
_logger.LogInformation("ReadList. Id:{Id}", model?.MessageId);
var list = model == null ? _storage.GetFullList() : _storage.GetFilteredList(model);
if (list == null)
{
_logger.LogWarning("ReadList return null list");
return null;
}
_logger.LogInformation("ReadList. Count:{Count}", list.Count);
return list;
}
public bool Create(MessageInfoBindingModel model)
{
if (_storage.Insert(model) == null)
{
_logger.LogInformation("Create operation failed");
return false;
}
return true;
}
}
}

View File

@ -1,4 +1,5 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopBusinessLogic.MailWorker;
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.BusinessLogicsContracts;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.StoragesContracts;
@ -10,6 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CarRepairShopBusinessLogic.BusinessLogics
{
@ -17,12 +19,16 @@ namespace CarRepairShopBusinessLogic.BusinessLogics
{
private readonly ILogger _logger;
private readonly IOrderStorage _orderStorage;
private readonly IClientStorage _clientStorage;
private readonly AbstractMailWorker _mailLogic;
static readonly object locker = new object();
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage)
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IClientStorage clientStorage, AbstractMailWorker worker)
{
_logger = logger;
_orderStorage = orderStorage;
_clientStorage = clientStorage;
_mailLogic = worker;
}
public List<OrderViewModel>? ReadList(OrderSearchModel? model)
@ -58,12 +64,16 @@ namespace CarRepairShopBusinessLogic.BusinessLogics
{
CheckModel(model);
model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null)
var order = _orderStorage.Insert(model);
if (order == null)
{
_logger.LogInformation("Create operation failed");
return false;
}
var clientView = _clientStorage.GetElement(new() { Id = order.ClientId });
SendMail(clientView, order);
return true;
}
@ -109,6 +119,12 @@ namespace CarRepairShopBusinessLogic.BusinessLogics
_logger.LogWarning("Update operation failed");
return false;
}
element.Status = newStatus;
var clientView = _clientStorage.GetElement(new() { Id = element.ClientId });
SendMail(clientView, element);
return true;
}
@ -132,5 +148,35 @@ namespace CarRepairShopBusinessLogic.BusinessLogics
}
_logger.LogInformation("Order. Id:{Id}. Sum:{Sum}. Count:{Count}", model.Id, model.Sum, model.Count);
}
private void SendMail(ClientViewModel clientModel, OrderViewModel orderModel)
{
if(clientModel == null || orderModel == null)
{
return;
}
MailSendInfoBindingModel mailModel;
if(orderModel.Status == OrderStatus.Принят)
{
mailModel = new MailSendInfoBindingModel
{
MailAddress = clientModel.Email,
Subject = $"Заказ №{orderModel.Id}",
Text = $"Ваш заказ №{orderModel.Id} на сумму {orderModel.Sum} был принят"
};
}
else
{
mailModel = new MailSendInfoBindingModel
{
MailAddress = clientModel.Email,
Subject = $"Заказ №{orderModel.Id}",
Text = $"Статус заказа №{orderModel.Id} был изменен на {orderModel.Status}"
};
}
_mailLogic.MailSendAsync(mailModel);
}
}
}

View File

@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageReference Include="MailKit" Version="4.5.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="MigraDocCore.DocumentObjectModel" Version="1.3.63" />
<PackageReference Include="MigraDocCore.Rendering" Version="1.3.63" />

View File

@ -0,0 +1,87 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp.Advanced;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopBusinessLogic.MailWorker
{
public abstract class AbstractMailWorker
{
protected string _mailLogin = string.Empty;
protected string _mailPassword = string.Empty;
protected string _smtpClientHost = string.Empty;
protected int _smtpClientPort;
protected string _popHost = string.Empty;
protected int _popPort;
private readonly IMessageInfoLogic _messageInfoLogic;
private readonly ILogger _logger;
public AbstractMailWorker(IMessageInfoLogic messageInfoLogic, ILogger<AbstractMailWorker> logger)
{
_messageInfoLogic = messageInfoLogic;
_logger = logger;
}
public void MailConfig(MailConfigBindingModel config)
{
_mailLogin = config.MailLogin;
_mailPassword = config.MailPassword;
_smtpClientHost = config.SmtpClientHost;
_smtpClientPort = config.SmtpClientPort;
_popHost = config.PopHost;
_popPort = config.PopPort;
_logger.LogDebug("Config: {login}, {password}, {clientHost}, {clientPOrt}, { popHost}, { popPort} ",
_mailLogin, _mailPassword, _smtpClientHost, _smtpClientPort, _popHost, _popPort);
}
public async void MailSendAsync(MailSendInfoBindingModel info)
{
if(string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{
return;
}
if(string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0)
{
return;
}
if(string.IsNullOrEmpty(info.MailAddress) || string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Text))
{
return;
}
_logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject);
await SendMailAsync(info);
}
public async void MailCheck()
{
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{
return;
}
if(string.IsNullOrEmpty(_popHost) || _popPort == 0)
{
return;
}
if(_messageInfoLogic == null)
{
return;
}
var list = await ReceiveMailAsync();
_logger.LogDebug("Check Mail: {Count} new mails", list.Count);
foreach(var mail in list)
{
_messageInfoLogic.Create(mail);
}
}
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
protected abstract Task<List<MessageInfoBindingModel>> ReceiveMailAsync();
}
}

View File

@ -0,0 +1,82 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.BusinessLogicsContracts;
using MailKit.Net.Pop3;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopBusinessLogic.MailWorker
{
public class MailKitWorker : AbstractMailWorker
{
public MailKitWorker(ILogger<MailKitWorker> logger, IMessageInfoLogic messageInfoLogic) : base(messageInfoLogic, logger) { }
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

@ -3,6 +3,7 @@ using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
namespace CarRepairShopClientApp.Controllers
@ -125,5 +126,15 @@ namespace CarRepairShopClientApp.Controllers
var rep = APIClient.GetRequest<RepairViewModel>($"api/main/getrepair?repairId={repair}");
return count * (rep?.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,52 @@
@using CarRepairShopContracts.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

@ -31,6 +31,9 @@
<li class="nav-item">
<a class="nav-link text-dark" asparea="" asp-controller="Home" asp-action="Privacy">Личные данные</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">Вход</a>
</li>

View File

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

View File

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

View File

@ -0,0 +1,24 @@
using CarRepairShopDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopContracts.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;
}
}

View File

@ -0,0 +1,17 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopContracts.BusinessLogicsContracts
{
public interface IMessageInfoLogic
{
List<MessageInfoViewModel>? ReadList(MessageInfoSearchModel? model);
bool Create(MessageInfoBindingModel model);
}
}

View File

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

View File

@ -0,0 +1,20 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopContracts.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,29 @@
using CarRepairShopDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopContracts.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,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopDataModels.Models
{
public interface IMessageInfoModel
{
string MessageId { get; }
int? ClientId { get; }
string SenderName { get; }
DateTime DateDelivery { get; }
string Subject { get; }
string Body { get; }
}
}

View File

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

View File

@ -31,12 +31,12 @@ namespace CarRepairShopDatabaseImplement.Implements
}
public ClientViewModel? GetElement(ClientSearchModel model)
{
if (string.IsNullOrEmpty(model.Email))
if (string.IsNullOrEmpty(model.Email) && !model.Id.HasValue)
{
return null;
}
using var context = new CarRepairShopDatabase();
return context.Clients.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Email)) && x.Email == model.Email || model.Id.HasValue && x.Id == model.Id)?.GetViewModel;
return context.Clients.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Email)) && x.Email.Contains(model.Email) || model.Id.HasValue && x.Id == model.Id)?.GetViewModel;
}
public ClientViewModel? Insert(ClientBindingModel model)
{

View File

@ -0,0 +1,47 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.StoragesContracts;
using CarRepairShopContracts.ViewModels;
using CarRepairShopDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopDatabaseImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
public List<MessageInfoViewModel> GetFullList()
{
using var context = new CarRepairShopDatabase();
return context.Messages.Include(x => x.Client).Select(x => x.GetViewModel).ToList();
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
if (!model.ClientId.HasValue) return new();
using var context = new CarRepairShopDatabase();
return context.Messages.Include(x => x.Client).Where(x => x.ClientId == model.ClientId).Select(x => x.GetViewModel).ToList();
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if(string.IsNullOrEmpty(model.MessageId)) return null;
using var context = new CarRepairShopDatabase();
return context.Messages.Include(x => x.Client).FirstOrDefault(x => x.MessageId.Equals(model.MessageId))?.GetViewModel;
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
using var context = new CarRepairShopDatabase();
model.ClientId = context.Clients.FirstOrDefault(x => x.Email.Equals(model.SenderName))?.Id;
var message = MessageInfo.Create(model);
if(message == null || context.Messages.Any(x => x.MessageId.Equals(model.MessageId))) return null;
context.Messages.Add(message);
context.SaveChanges();
return message.GetViewModel;
}
}
}

View File

@ -12,8 +12,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace CarRepairShopDatabaseImplement.Migrations
{
[DbContext(typeof(CarRepairShopDatabase))]
[Migration("20240420181926_InitialCreate")]
partial class InitialCreate
[Migration("20240505094524_InitMigration")]
partial class InitMigration
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -97,6 +97,36 @@ namespace CarRepairShopDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("CarRepairShopDatabaseImplement.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("CarRepairShopDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -186,6 +216,15 @@ namespace CarRepairShopDatabaseImplement.Migrations
b.ToTable("RepairComponents");
});
modelBuilder.Entity("CarRepairShopDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("CarRepairShopDatabaseImplement.Models.Client", "Client")
.WithMany()
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("CarRepairShopDatabaseImplement.Models.Order", b =>
{
b.HasOne("CarRepairShopDatabaseImplement.Models.Client", "Client")

View File

@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace CarRepairShopDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
public partial class InitMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
@ -70,6 +70,27 @@ namespace CarRepairShopDatabaseImplement.Migrations
table.PrimaryKey("PK_Repairs", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Messages",
columns: table => new
{
MessageId = table.Column<string>(type: "nvarchar(450)", nullable: false),
ClientId = table.Column<int>(type: "int", nullable: true),
SenderName = table.Column<string>(type: "nvarchar(max)", nullable: false),
DateDelivery = table.Column<DateTime>(type: "datetime2", nullable: false),
Subject = table.Column<string>(type: "nvarchar(max)", nullable: false),
Body = table.Column<string>(type: "nvarchar(max)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Messages", x => x.MessageId);
table.ForeignKey(
name: "FK_Messages_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Orders",
columns: table => new
@ -134,6 +155,11 @@ namespace CarRepairShopDatabaseImplement.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Messages_ClientId",
table: "Messages",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_Orders_ClientId",
table: "Orders",
@ -163,6 +189,9 @@ namespace CarRepairShopDatabaseImplement.Migrations
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Messages");
migrationBuilder.DropTable(
name: "Orders");

View File

@ -94,6 +94,36 @@ namespace CarRepairShopDatabaseImplement.Migrations
b.ToTable("Implementers");
});
modelBuilder.Entity("CarRepairShopDatabaseImplement.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("CarRepairShopDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
@ -183,6 +213,15 @@ namespace CarRepairShopDatabaseImplement.Migrations
b.ToTable("RepairComponents");
});
modelBuilder.Entity("CarRepairShopDatabaseImplement.Models.MessageInfo", b =>
{
b.HasOne("CarRepairShopDatabaseImplement.Models.Client", "Client")
.WithMany()
Review

Связь настроена не до конца

Связь настроена не до конца
.HasForeignKey("ClientId");
b.Navigation("Client");
});
modelBuilder.Entity("CarRepairShopDatabaseImplement.Models.Order", b =>
{
b.HasOne("CarRepairShopDatabaseImplement.Models.Client", "Client")

View File

@ -0,0 +1,55 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.ViewModels;
using CarRepairShopDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopDatabaseImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
[Key]
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
[Required]
public string SenderName { get; set; } = string.Empty;
[Required]
public DateTime DateDelivery { get; set; }
[Required]
public string Subject { get; set; } = string.Empty;
[Required]
public string Body { get; set; } = string.Empty;
public virtual Client Client { get; private 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

@ -16,11 +16,13 @@ namespace CarRepairShopFileImplement
private readonly string RepairFileName = "Repair.xml";
private readonly string ClientFileName = "Client.xml";
private readonly string ImplementerFileName = "Implementer.xml";
private readonly string MessagesFileName = "MessageInfo.xml";
public List<Component> Components { get; private set; }
public List<Order> Orders { get; private set; }
public List<Repair> Repairs { 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)
@ -34,6 +36,7 @@ namespace CarRepairShopFileImplement
public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement);
public void SaveClients() => SaveData(Clients, ClientFileName, "Clients", x => x.GetXElement);
public void SaveImplementers() => SaveData(Implementers, ImplementerFileName, "Implementers", x => x.GetXElement);
public void SaveMessages() => SaveData(Messages, MessagesFileName, "Messages", x => x.GetXElement);
private DataFileSingleton()
{
Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!;
@ -41,6 +44,7 @@ namespace CarRepairShopFileImplement
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(MessagesFileName, "MessageInfo", x => MessageInfo.Create(x)!)!;
}
private static List<T>? LoadData<T>(string filename, string xmlNodeName, Func<XElement, T> selectFunction)
{

View File

@ -35,7 +35,7 @@ namespace CarRepairShopFileImplement.Implements
public ClientViewModel? GetElement(ClientSearchModel model)
{
if (string.IsNullOrEmpty(model.Email) && !model.Id.HasValue) return null;
return source.Clients.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Email) && x.Email == model.Email) || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel;
return source.Clients.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Email) && x.Email.Contains(model.Email)) || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel;
}
public ClientViewModel? Insert(ClientBindingModel model)

View File

@ -0,0 +1,47 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.StoragesContracts;
using CarRepairShopContracts.ViewModels;
using CarRepairShopFileImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopFileImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
private readonly DataFileSingleton _source;
public MessageInfoStorage()
{
_source = DataFileSingleton.GetInstance();
}
public List<MessageInfoViewModel> GetFullList()
{
return _source.Messages.Select(x => x.GetViewModel).ToList();
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
if (model == null) return new();
return _source.Messages.Where(x => x.ClientId == model.ClientId).Select(x => x.GetViewModel).ToList();
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if(model == null) return null;
return _source.Messages.FirstOrDefault(x => x.MessageId.Equals(model.MessageId))?.GetViewModel;
}
public MessageInfoViewModel? Insert(MessageInfoBindingModel model)
{
if (model == null) return null;
var newMessage = MessageInfo.Create(model);
if(newMessage == null) return null;
_source.Messages.Add(newMessage);
_source.SaveMessages();
return newMessage.GetViewModel;
}
}
}

View File

@ -0,0 +1,74 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.ViewModels;
using CarRepairShopDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace CarRepairShopFileImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; }
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel? model)
{
if (model == null) return null;
return new MessageInfo()
{
MessageId = model.MessageId,
ClientId = model.ClientId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
Subject = model.Subject,
Body = model.Body,
};
}
public static MessageInfo? Create(XElement element)
{
if (element == null) return null;
return new MessageInfo()
{
MessageId = element.Attribute("MessageId")!.Value,
ClientId = Convert.ToInt32(element.Attribute("ClientId")!.Value),
SenderName = element.Element("SenderName")!.Value,
DateDelivery = Convert.ToDateTime(element.Element("DateDelivery")!.Value),
Subject = element.Attribute("Subject")!.Value,
Body = element.Attribute("Body")!.Value,
};
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
};
public XElement GetXElement => new("MessageInfo",
new XAttribute("MessageId", MessageId.ToString()),
new XElement("ClientId", ClientId.ToString()),
new XElement("SenderName", SenderName),
new XElement("DateDelivery", DateDelivery),
new XElement("Subject", Subject),
new XElement("Body", Body),
new XElement("SenderName", SenderName));
}
}

View File

@ -10,6 +10,7 @@ namespace CarRepairShopListImplement
public List<Order> Orders { get; set; }
public List<Client> Clients { get; set; }
public List<Implementer> Implementers { get; set; }
public List<MessageInfo> Messages { get; set; }
private DataListSingleton()
{
@ -18,6 +19,7 @@ namespace CarRepairShopListImplement
Orders = new List<Order>();
Clients = new List<Client>();
Implementers = new List<Implementer>();
Messages = new List<MessageInfo>();
}
public static DataListSingleton GetInstance()

View File

@ -45,7 +45,7 @@ namespace CarRepairShopListImplement.Implements
if(string.IsNullOrEmpty(model.Email) && !model.Id.HasValue) return null;
foreach (var client in _source.Clients)
{
if((!string.IsNullOrEmpty(model.Email) && client.Email == model.Email) || (model.Id.HasValue && client.Id == model.Id))
if((!string.IsNullOrEmpty(model.Email) && client.Email.Contains(model.Email)) || (model.Id.HasValue && client.Id == model.Id))
{
return client.GetViewModel;
}

View File

@ -0,0 +1,67 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.SearchModels;
using CarRepairShopContracts.StoragesContracts;
using CarRepairShopContracts.ViewModels;
using CarRepairShopListImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopListImplement.Implements
{
public class MessageInfoStorage : IMessageInfoStorage
{
private readonly DataListSingleton _source;
public MessageInfoStorage()
{
_source = DataListSingleton.GetInstance();
}
public List<MessageInfoViewModel> GetFullList()
{
var list = new List<MessageInfoViewModel>();
foreach(var message in _source.Messages)
{
list.Add(message.GetViewModel);
}
return list;
}
public List<MessageInfoViewModel> GetFilteredList(MessageInfoSearchModel model)
{
var list = new List<MessageInfoViewModel>();
if(!model.ClientId.HasValue) return list;
foreach(var message in _source.Messages)
{
if(model.ClientId == message.ClientId)
{
list.Add(message.GetViewModel);
}
}
return list;
}
public MessageInfoViewModel? GetElement(MessageInfoSearchModel model)
{
if(string.IsNullOrEmpty(model.MessageId)) return null;
foreach(var message in _source.Messages)
{
if (model.MessageId.Equals(model.MessageId))
{
return message.GetViewModel;
}
}
return null;
}
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,50 @@
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.ViewModels;
using CarRepairShopDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarRepairShopListImplement.Models
{
public class MessageInfo : IMessageInfoModel
{
public string MessageId { get; set; } = string.Empty;
public int? ClientId { get; set; }
public string SenderName { get; set; } = string.Empty;
public DateTime DateDelivery { get; set; }
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public static MessageInfo? Create(MessageInfoBindingModel model)
{
if (model == null) return null;
return new MessageInfo()
{
MessageId = model.MessageId,
ClientId = model.ClientId,
SenderName = model.SenderName,
DateDelivery = model.DateDelivery,
Subject = model.Subject,
Body = model.Body,
};
}
public MessageInfoViewModel GetViewModel => new()
{
MessageId = MessageId,
ClientId = ClientId,
SenderName = SenderName,
DateDelivery = DateDelivery,
Subject = Subject,
Body = Body,
};
}
}

View File

@ -13,11 +13,13 @@ namespace CarRepairShopRestApi.Controllers
{
private readonly ILogger _logger;
private readonly IClientLogic _logic;
private readonly IMessageInfoLogic _mailLogic;
public ClientController(IClientLogic logic, ILogger<ClientController> logger)
public ClientController(IClientLogic logic, ILogger<ClientController> logger, IMessageInfoLogic mailLogic)
{
_logic = logic;
_logger = logger;
_mailLogic = mailLogic;
}
[HttpGet]
@ -65,5 +67,22 @@ namespace CarRepairShopRestApi.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 CarRepairShopBusinessLogic.BusinessLogics;
using CarRepairShopBusinessLogic.MailWorker;
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.BusinessLogicsContracts;
using CarRepairShopContracts.StoragesContracts;
using CarRepairShopDatabaseImplement.Implements;
@ -14,10 +16,16 @@ builder.Logging.AddLog4Net("log4net.config");
builder.Services.AddTransient<IClientStorage, ClientStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<IRepairStorage, RepairStorage>();
builder.Services.AddTransient<IComponentStorage, ComponentStorage>();
builder.Services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<IRepairLogic, RepairLogic>();
builder.Services.AddTransient<IComponentLogic, ComponentLogic>();
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
@ -33,6 +41,18 @@ 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.mail.ru",
"SmtpClientPort": "587",
"PopHost": "pop.mail.ru",
"PopPort": "995",
"MailLogin": "labwork7@mail.ru",
"MailPassword": "i135ssgqi7jEzphpyVH9"
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SmtpClientHost" value="smtp.mail.ru" />
<add key="SmtpClientPort" value="587" />
<add key="PopHost" value="pop.mail.ru" />
<add key="PopPort" value="995" />
<add key="MailLogin" value="labwork7@mail.ru" />
<add key="MailPassword" value="i135ssgqi7jEzphpyVH9" />
</appSettings>
</configuration>

View File

@ -42,4 +42,10 @@
<ProjectReference Include="..\CarRepairShopListImplement\CarRepairShopListImplement.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="App.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,67 @@
namespace CarRepairShopView
{
partial class FormLetters
{
/// <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.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dataGridView.BackgroundColor = Color.White;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Dock = DockStyle.Fill;
dataGridView.Location = new Point(0, 0);
dataGridView.Name = "dataGridView";
dataGridView.ReadOnly = true;
dataGridView.RowHeadersVisible = false;
dataGridView.RowTemplate.Height = 25;
dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView.Size = new Size(800, 450);
dataGridView.TabIndex = 2;
//
// FormLetters
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(dataGridView);
Name = "FormLetters";
Text = "Письма";
Load += FormLetters_Load;
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView;
}
}

View File

@ -0,0 +1,39 @@
using CarRepairShopContracts.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CarRepairShopView
{
public partial class FormLetters : Form
{
private readonly ILogger _logger;
private readonly IMessageInfoLogic _logic;
public FormLetters(ILogger<FormLetters> logger, IMessageInfoLogic logic)
{
InitializeComponent();
_logger = logger;
_logic = logic;
}
private void FormLetters_Load(object sender, EventArgs e)
{
_logger.LogInformation("Загрузка писем");
var list = _logic.ReadList(null);
if(list != null )
{
dataGridView.DataSource = list;
dataGridView.Columns["MessageId"].Visible = false;
dataGridView.Columns["ClientId"].Visible = false;
}
}
}
}

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

@ -38,18 +38,19 @@
OrdersToolStripMenuItem = new ToolStripMenuItem();
ClientsToolStripMenuItem = new ToolStripMenuItem();
workStartToolStripMenuItem = new ToolStripMenuItem();
implementersToolStripMenuItem = new ToolStripMenuItem();
dataGridView = new DataGridView();
buttonCreateOrder = new Button();
buttonIssuedOrder = new Button();
buttonRef = new Button();
implementersToolStripMenuItem = new ToolStripMenuItem();
почтаToolStripMenuItem = new ToolStripMenuItem();
menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
//
// menuStrip1
//
menuStrip1.Items.AddRange(new ToolStripItem[] { справочникиToolStripMenuItem, отчетыToolStripMenuItem, ClientsToolStripMenuItem, workStartToolStripMenuItem, implementersToolStripMenuItem });
menuStrip1.Items.AddRange(new ToolStripItem[] { справочникиToolStripMenuItem, отчетыToolStripMenuItem, ClientsToolStripMenuItem, workStartToolStripMenuItem, implementersToolStripMenuItem, почтаToolStripMenuItem });
menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1";
menuStrip1.Size = new Size(1059, 24);
@ -119,6 +120,13 @@
workStartToolStripMenuItem.Text = "Запуск работ";
workStartToolStripMenuItem.Click += workStartToolStripMenuItem_Click;
//
// implementersToolStripMenuItem
//
implementersToolStripMenuItem.Name = "implementersToolStripMenuItem";
implementersToolStripMenuItem.Size = new Size(94, 20);
implementersToolStripMenuItem.Text = "Исполнители";
implementersToolStripMenuItem.Click += implementersToolStripMenuItem_Click;
//
// dataGridView
//
dataGridView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
@ -167,12 +175,12 @@
buttonRef.UseVisualStyleBackColor = true;
buttonRef.Click += buttonRef_Click;
//
// implementersToolStripMenuItem
// почтаToolStripMenuItem
//
implementersToolStripMenuItem.Name = "implementersToolStripMenuItem";
implementersToolStripMenuItem.Size = new Size(94, 20);
implementersToolStripMenuItem.Text = "Исполнители";
implementersToolStripMenuItem.Click += implementersToolStripMenuItem_Click;
почтаToolStripMenuItem.Name = "почтаToolStripMenuItem";
почтаToolStripMenuItem.Size = new Size(53, 20);
почтаToolStripMenuItem.Text = "Почта";
почтаToolStripMenuItem.Click += почтаToolStripMenuItem_Click;
//
// FormMain
//
@ -212,5 +220,6 @@
private ToolStripMenuItem ClientsToolStripMenuItem;
private ToolStripMenuItem workStartToolStripMenuItem;
private ToolStripMenuItem implementersToolStripMenuItem;
private ToolStripMenuItem почтаToolStripMenuItem;
}
}

View File

@ -208,7 +208,16 @@ namespace CarRepairShopView
private void implementersToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormImplementers));
if(service is FormImplementers form)
if (service is FormImplementers form)
{
form.ShowDialog();
}
}
private void почтаToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormLetters));
if (service is FormLetters form)
{
form.ShowDialog();
}

View File

@ -1,6 +1,8 @@
using CarRepairShopBusinessLogic.BusinessLogics;
using CarRepairShopBusinessLogic.MailWorker;
using CarRepairShopBusinessLogic.OfficePackage;
using CarRepairShopBusinessLogic.OfficePackage.Implements;
using CarRepairShopContracts.BindingModels;
using CarRepairShopContracts.BusinessLogicsContracts;
using CarRepairShopContracts.StoragesContracts;
using CarRepairShopDatabaseImplement.Implements;
@ -28,6 +30,26 @@ namespace CarRepairShopView
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>());
}
@ -44,6 +66,7 @@ namespace CarRepairShopView
services.AddTransient<IRepairStorage, RepairStorage>();
services.AddTransient<IClientStorage, ClientStorage>();
services.AddTransient<IImplementerStorage, ImplementerStorage>();
services.AddTransient<IMessageInfoStorage, MessageInfoStorage>();
services.AddTransient<IComponentLogic, ComponentLogic>();
services.AddTransient<IOrderLogic, OrderLogic>();
@ -51,7 +74,10 @@ namespace CarRepairShopView
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>();
@ -69,6 +95,8 @@ namespace CarRepairShopView
services.AddTransient<FormClients>();
services.AddTransient<FormImplementer>();
services.AddTransient<FormImplementers>();
services.AddTransient<FormLetters>();
}
private static void MailCheck(object obj) => ServiceProvider?.GetService<AbstractMailWorker>()?.MailCheck();
}
}