diff --git a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs index 4e3a819..26fd495 100644 --- a/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs +++ b/ComputersShop/ComputersShopBusinessLogic/BusinessLogics/MessageInfoLogic.cs @@ -16,11 +16,13 @@ namespace ComputersShopBusinessLogic.BusinessLogics { private readonly ILogger _logger; private readonly IMessageInfoStorage _messageInfoStorage; + private readonly IClientStorage _clientStorage; - public MessageInfoLogic(ILogger logger, IMessageInfoStorage messageInfoStorage) + public MessageInfoLogic(ILogger logger, IMessageInfoStorage messageInfoStorage, IClientStorage clientStorage) { _logger = logger; _messageInfoStorage = messageInfoStorage; + _clientStorage = clientStorage; } public bool Create(MessageInfoBindingModel model) @@ -45,5 +47,47 @@ namespace ComputersShopBusinessLogic.BusinessLogics _logger.LogInformation("ReadList. Count:{Count}", list.Count); return list; } + + private void CheckModel(MessageInfoBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.MessageId)) + { + throw new ArgumentNullException("Не указан id сообщения", nameof(model.MessageId)); + } + if (string.IsNullOrEmpty(model.SenderName)) + { + throw new ArgumentNullException("Не указао почта", nameof(model.SenderName)); + } + if (string.IsNullOrEmpty(model.Subject)) + { + throw new ArgumentNullException("Не указана тема", nameof(model.Subject)); + } + if (string.IsNullOrEmpty(model.Body)) + { + throw new ArgumentNullException("Не указан текст сообщения", nameof(model.Subject)); + } + + _logger.LogInformation("MessageInfo. MessageId:{MessageId}.SenderName:{SenderName}.Subject:{Subject}.Body:{Body}", model.MessageId, model.SenderName, model.Subject, model.Body); + var element = _clientStorage.GetElement(new ClientSearchModel + { + Email = model.SenderName + }); + if (element == null) + { + _logger.LogWarning("Не удалоссь найти клиента, отправившего письмо с адреса Email:{Email}", model.SenderName); + } + else + { + model.ClientId = element.Id; + } + } } } diff --git a/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs b/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs index f7c439e..a60c65d 100644 --- a/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs +++ b/ComputersShop/ComputersShopContracts/ViewModels/OrderViewModel.cs @@ -17,6 +17,7 @@ namespace ComputersShopContracts.ViewModels public int ClientId { get; set; } [DisplayName("Фамилия клиента")] public string ClientFIO { get; set; } = string.Empty; + public string ClientEmail { get; set; } = string.Empty; public int? ImplementerId { get; set; } [DisplayName("Исполнитель")] public string ImplementerFIO { get; set; } = string.Empty; diff --git a/ComputersShop/ComputersShopDataBaseImplement/Implements/ClientStorage.cs b/ComputersShop/ComputersShopDataBaseImplement/Implements/ClientStorage.cs index b34954a..74c5cc8 100644 --- a/ComputersShop/ComputersShopDataBaseImplement/Implements/ClientStorage.cs +++ b/ComputersShop/ComputersShopDataBaseImplement/Implements/ClientStorage.cs @@ -27,17 +27,21 @@ namespace ComputersShopDataBaseImplement.Implements public ClientViewModel? GetElement(ClientSearchModel model) { + if (string.IsNullOrEmpty(model.ClientFIO) && + string.IsNullOrEmpty(model.Email) && + string.IsNullOrEmpty(model.Password) && + !model.Id.HasValue) + { + return null; + } using var context = new ComputersShopDataBase(); - if (model.Id.HasValue) - return context.Clients.FirstOrDefault(x => x.Id == model.Id)?.GetViewModel; - if (model.Email != null && model.Password != null) - return context.Clients - .FirstOrDefault(x => x.Email.Equals(model.Email) - && x.Password.Equals(model.Password)) - ?.GetViewModel; - if (model.Email != null) - return context.Clients.FirstOrDefault(x => x.Email.Equals(model.Email))?.GetViewModel; - return null; + var temp = context.Clients + .FirstOrDefault(x => (string.IsNullOrEmpty(model.ClientFIO) || x.ClientFIO == model.ClientFIO) && + (string.IsNullOrEmpty(model.Email) || x.Email == model.Email) && + (string.IsNullOrEmpty(model.Password) || x.Password == model.Password) && + (!model.Id.HasValue || x.Id == model.Id)) + ?.GetViewModel; + return temp; } public List GetFilteredList(ClientSearchModel model) diff --git a/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240414115616_InitialCreate.Designer.cs b/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240418105123_Init-Create.Designer.cs similarity index 86% rename from ComputersShop/ComputersShopDataBaseImplement/Migrations/20240414115616_InitialCreate.Designer.cs rename to ComputersShop/ComputersShopDataBaseImplement/Migrations/20240418105123_Init-Create.Designer.cs index b3f7bb0..8c7fd9c 100644 --- a/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240414115616_InitialCreate.Designer.cs +++ b/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240418105123_Init-Create.Designer.cs @@ -12,8 +12,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace ComputersShopDataBaseImplement.Migrations { [DbContext(typeof(ComputersShopDataBase))] - [Migration("20240414115616_InitialCreate")] - partial class InitialCreate + [Migration("20240418105123_Init-Create")] + partial class InitCreate { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -143,6 +143,36 @@ namespace ComputersShopDataBaseImplement.Migrations b.ToTable("Implementers"); }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Message", b => + { + b.Property("MessageId") + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("DateDelivery") + .HasColumnType("timestamp with time zone"); + + b.Property("SenderName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.ToTable("Messages"); + }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Order", b => { b.Property("Id") @@ -205,6 +235,13 @@ namespace ComputersShopDataBaseImplement.Migrations b.Navigation("Computer"); }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Message", b => + { + b.HasOne("ComputersShopDataBaseImplement.Models.Client", null) + .WithMany("Messages") + .HasForeignKey("ClientId"); + }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Order", b => { b.HasOne("ComputersShopDataBaseImplement.Models.Client", "Client") @@ -232,6 +269,8 @@ namespace ComputersShopDataBaseImplement.Migrations modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Client", b => { + b.Navigation("Messages"); + b.Navigation("Orders"); }); diff --git a/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240414115616_InitialCreate.cs b/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240418105123_Init-Create.cs similarity index 85% rename from ComputersShop/ComputersShopDataBaseImplement/Migrations/20240414115616_InitialCreate.cs rename to ComputersShop/ComputersShopDataBaseImplement/Migrations/20240418105123_Init-Create.cs index 23a3db3..a29f95b 100644 --- a/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240414115616_InitialCreate.cs +++ b/ComputersShop/ComputersShopDataBaseImplement/Migrations/20240418105123_Init-Create.cs @@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace ComputersShopDataBaseImplement.Migrations { /// - public partial class InitialCreate : Migration + public partial class InitCreate : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -71,6 +71,27 @@ namespace ComputersShopDataBaseImplement.Migrations table.PrimaryKey("PK_Implementers", x => x.Id); }); + migrationBuilder.CreateTable( + name: "Messages", + columns: table => new + { + MessageId = table.Column(type: "text", nullable: false), + ClientId = table.Column(type: "integer", nullable: true), + SenderName = table.Column(type: "text", nullable: false), + DateDelivery = table.Column(type: "timestamp with time zone", nullable: false), + Subject = table.Column(type: "text", nullable: false), + Body = table.Column(type: "text", 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: "ComputerComponents", columns: table => new @@ -145,6 +166,11 @@ namespace ComputersShopDataBaseImplement.Migrations table: "ComputerComponents", column: "ComputerId"); + migrationBuilder.CreateIndex( + name: "IX_Messages_ClientId", + table: "Messages", + column: "ClientId"); + migrationBuilder.CreateIndex( name: "IX_Orders_ClientId", table: "Orders", @@ -167,6 +193,9 @@ namespace ComputersShopDataBaseImplement.Migrations migrationBuilder.DropTable( name: "ComputerComponents"); + migrationBuilder.DropTable( + name: "Messages"); + migrationBuilder.DropTable( name: "Orders"); diff --git a/ComputersShop/ComputersShopDataBaseImplement/Migrations/ComputersShopDataBaseModelSnapshot.cs b/ComputersShop/ComputersShopDataBaseImplement/Migrations/ComputersShopDataBaseModelSnapshot.cs index 063d3da..5e2413c 100644 --- a/ComputersShop/ComputersShopDataBaseImplement/Migrations/ComputersShopDataBaseModelSnapshot.cs +++ b/ComputersShop/ComputersShopDataBaseImplement/Migrations/ComputersShopDataBaseModelSnapshot.cs @@ -140,6 +140,36 @@ namespace ComputersShopDataBaseImplement.Migrations b.ToTable("Implementers"); }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Message", b => + { + b.Property("MessageId") + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("DateDelivery") + .HasColumnType("timestamp with time zone"); + + b.Property("SenderName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.ToTable("Messages"); + }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Order", b => { b.Property("Id") @@ -202,6 +232,13 @@ namespace ComputersShopDataBaseImplement.Migrations b.Navigation("Computer"); }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Message", b => + { + b.HasOne("ComputersShopDataBaseImplement.Models.Client", null) + .WithMany("Messages") + .HasForeignKey("ClientId"); + }); + modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Order", b => { b.HasOne("ComputersShopDataBaseImplement.Models.Client", "Client") @@ -229,6 +266,8 @@ namespace ComputersShopDataBaseImplement.Migrations modelBuilder.Entity("ComputersShopDataBaseImplement.Models.Client", b => { + b.Navigation("Messages"); + b.Navigation("Orders"); }); diff --git a/ComputersShop/ComputersShopDataBaseImplement/Models/Client.cs b/ComputersShop/ComputersShopDataBaseImplement/Models/Client.cs index b276ec4..facae9d 100644 --- a/ComputersShop/ComputersShopDataBaseImplement/Models/Client.cs +++ b/ComputersShop/ComputersShopDataBaseImplement/Models/Client.cs @@ -28,6 +28,9 @@ namespace ComputersShopDataBaseImplement.Models [ForeignKey("ClientId")] public virtual List Orders { get; set; } = new(); + [ForeignKey("ClientId")] + public virtual List Messages { get; set; } = new(); + public static Client? Create(ClientBindingModel model) { if (model == null) diff --git a/ComputersShop/ComputersShopDataBaseImplement/Models/Order.cs b/ComputersShop/ComputersShopDataBaseImplement/Models/Order.cs index 48c9fe8..a4f31e1 100644 --- a/ComputersShop/ComputersShopDataBaseImplement/Models/Order.cs +++ b/ComputersShop/ComputersShopDataBaseImplement/Models/Order.cs @@ -70,6 +70,7 @@ namespace ComputersShopDataBaseImplement.Models ComputerId = ComputerId, ClientId = ClientId, ClientFIO = Client.ClientFIO, + ClientEmail = Client.Email, ImplementerId = ImplementerId, ImplementerFIO = Implementer?.ImplementerFIO ?? string.Empty, Count = Count, diff --git a/ComputersShop/ComputersShopRestAPI/ComputersShopRestApi.csproj b/ComputersShop/ComputersShopRestAPI/ComputersShopRestApi.csproj index 6a0d8b7..c9c0d76 100644 --- a/ComputersShop/ComputersShopRestAPI/ComputersShopRestApi.csproj +++ b/ComputersShop/ComputersShopRestAPI/ComputersShopRestApi.csproj @@ -18,6 +18,9 @@ + + PreserveNewest + Always diff --git a/ComputersShop/ComputersShopRestAPI/Controllers/ClientController.cs b/ComputersShop/ComputersShopRestAPI/Controllers/ClientController.cs index 0b801a7..66eaac2 100644 --- a/ComputersShop/ComputersShopRestAPI/Controllers/ClientController.cs +++ b/ComputersShop/ComputersShopRestAPI/Controllers/ClientController.cs @@ -6,65 +6,85 @@ using Microsoft.AspNetCore.Mvc; namespace ComputersShopRestApi.Controllers { - [Route("api/[controller]/[action]")] - [ApiController] - public class ClientController : Controller - { - private readonly ILogger _logger; + [Route("api/[controller]/[action]")] + [ApiController] + public class ClientController : Controller + { + private readonly ILogger _logger; - private readonly IClientLogic _logic; + private readonly IClientLogic _logic; - public ClientController(IClientLogic logic, ILogger logger) - { - _logger = logger; - _logic = logic; - } + private readonly IMessageInfoLogic _mailLogic; - [HttpGet] - public ClientViewModel? Login(string login, string password) - { - try - { - return _logic.ReadElement(new ClientSearchModel - { - Email = login, - Password = password - }); + public ClientController(IClientLogic logic, ILogger logger, IMessageInfoLogic mailLogic) + { + _logger = logger; + _logic = logic; + _mailLogic = mailLogic; + } - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка входа в систему"); - throw; - } - } + [HttpGet] + public ClientViewModel? Login(string login, string password) + { + try + { + return _logic.ReadElement(new ClientSearchModel + { + Email = login, + Password = password + }); - [HttpPost] - public void Register(ClientBindingModel model) - { - try - { - _logic.Create(model); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка регистрации"); - throw; - } - } + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка входа в систему"); + throw; + } + } - [HttpPost] - public void UpdateData(ClientBindingModel model) - { - try - { - _logic.Update(model); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка обновления данных"); - throw; - } - } - } + [HttpPost] + public void Register(ClientBindingModel model) + { + try + { + _logic.Create(model); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка регистрации"); + throw; + } + } + + [HttpPost] + public void UpdateData(ClientBindingModel model) + { + try + { + _logic.Update(model); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка обновления данных"); + throw; + } + } + + [HttpGet] + public List? GetMessages(int clientId) + { + try + { + return _mailLogic.ReadList(new MessageInfoSearchModel + { + ClientId = clientId + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка получения писем клиента"); + throw; + } + } + } } diff --git a/ComputersShop/ComputersShopRestAPI/Program.cs b/ComputersShop/ComputersShopRestAPI/Program.cs index 2ab530f..02eb6d9 100644 --- a/ComputersShop/ComputersShopRestAPI/Program.cs +++ b/ComputersShop/ComputersShopRestAPI/Program.cs @@ -1,4 +1,6 @@ using ComputersShopBusinessLogic.BusinessLogics; +using ComputersShopBusinessLogic.MailWorker; +using ComputersShopContracts.BindingModels; using ComputersShopContracts.BusinessLogicContracts; using ComputersShopContracts.StoragesContracts; using ComputersShopDataBaseImplement.Implements; @@ -11,34 +13,47 @@ builder.Logging.AddLog4Net("log4net.config"); // Add services to the container. builder.Services.AddTransient(); -builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddTransient(); -builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); + +builder.Services.AddSingleton(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { - c.SwaggerDoc("v1", new OpenApiInfo - { - Title = "ComputersShopRestApi", - Version = "v1" - }); + c.SwaggerDoc("v1", new OpenApiInfo + { + Title = "ComputersShopRestApi", + Version = "v1" + }); }); var app = builder.Build(); +var mailSender = app.Services.GetService(); +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()) { - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ComputersShopRestApi v1")); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ComputersShopRestApi v1")); } app.UseHttpsRedirection(); diff --git a/ComputersShop/ComputersShopRestAPI/appsettings.json b/ComputersShop/ComputersShopRestAPI/appsettings.json index 04d60c9..2b24c1f 100644 --- a/ComputersShop/ComputersShopRestAPI/appsettings.json +++ b/ComputersShop/ComputersShopRestAPI/appsettings.json @@ -11,6 +11,6 @@ "SmtpClientPort": "587", "PopHost": "pop.gmail.com", "PopPort": "995", - "MailLogin": "rpplabs24@gmail.com", - "MailPassword": "qqwezxc2024" + "MailLogin": "rpplabs724@gmail.com", + "MailPassword": "qqeqweeeq24zxc" } diff --git a/ComputersShop/ComputersShopView/App.config b/ComputersShop/ComputersShopView/App.config index afed655..47747e2 100644 --- a/ComputersShop/ComputersShopView/App.config +++ b/ComputersShop/ComputersShopView/App.config @@ -5,7 +5,7 @@ - - + + \ No newline at end of file diff --git a/ComputersShop/ComputersShopView/ComputersShopView.csproj b/ComputersShop/ComputersShopView/ComputersShopView.csproj index f916865..2b9f36f 100644 --- a/ComputersShop/ComputersShopView/ComputersShopView.csproj +++ b/ComputersShop/ComputersShopView/ComputersShopView.csproj @@ -29,4 +29,10 @@ + + + Always + + + \ No newline at end of file