diff --git a/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/Storekeeper/ReportStorekeeperLogic.cs b/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/Storekeeper/ReportStorekeeperLogic.cs index f514eae..495d709 100644 --- a/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/Storekeeper/ReportStorekeeperLogic.cs +++ b/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/Storekeeper/ReportStorekeeperLogic.cs @@ -1,4 +1,5 @@ -using HardwareShopBusinessLogic.OfficePackage; +using HardwareShopBusinessLogic.MailWorker; +using HardwareShopBusinessLogic.OfficePackage; using HardwareShopBusinessLogic.OfficePackage.HelperModels; using HardwareShopContracts.BindingModels; using HardwareShopContracts.BusinessLogicsContracts; @@ -13,16 +14,22 @@ namespace HardwareShopBusinessLogic.BusinessLogics.Storekeeper private readonly IGoodStorage _goodStorage; + private readonly IUserStorage _userStorage; + private readonly AbstractSaveToExcel _saveToExcel; private readonly AbstractSaveToWord _saveToWord; - public ReportStorekeeperLogic(IComponentStorage componentStorage, AbstractSaveToExcel abstractSaveToExcel, AbstractSaveToWord abstractSaveToWord, IGoodStorage goodStorage) + private readonly AbstractMailWorker _mailWorker; + + public ReportStorekeeperLogic(IComponentStorage componentStorage, AbstractSaveToExcel abstractSaveToExcel, AbstractSaveToWord abstractSaveToWord, IGoodStorage goodStorage, AbstractMailWorker abstractMailWorker, IUserStorage userStorage) { _componentStorage = componentStorage; _saveToExcel = abstractSaveToExcel; _saveToWord = abstractSaveToWord; _goodStorage = goodStorage; + _mailWorker = abstractMailWorker; + _userStorage = userStorage; } public List GetBuildGood(List goods) { @@ -109,5 +116,18 @@ namespace HardwareShopBusinessLogic.BusinessLogics.Storekeeper File.Delete(model.FileName); return file; } + + public bool SendReportOnMail(int userId, string subject, string text) + { + var user = _userStorage.GetElement(new() { Id = userId }); + if (user == null) return false; + _mailWorker.MailSendAsync(new() + { + MailAddress = user.Email, + Subject = subject, + Text = text + }); + return true; + } } } diff --git a/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/UserLogic.cs b/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/UserLogic.cs index 701f6f5..e19b7fb 100644 --- a/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/UserLogic.cs +++ b/HardwareShop/HardwareShopBusinessLogic/BusinessLogics/UserLogic.cs @@ -94,19 +94,19 @@ namespace HardwareShopBusinessLogic.BusinessLogics { return; } - if (string.IsNullOrEmpty(model.Login) || model.Login.Length > 20) + if (string.IsNullOrEmpty(model.Login) || model.Login.Length > 40) { - throw new ArgumentNullException("Нет логина пользователя или длина превышает 20 символов", nameof(model.Login)); + throw new ArgumentNullException("Нет логина пользователя или длина превышает 40 символов", nameof(model.Login)); } - if (string.IsNullOrEmpty(model.Email) || model.Email.Length > 30) + if (string.IsNullOrEmpty(model.Email) || model.Email.Length > 40) { - throw new ArgumentNullException("Нет почты пользователя или длина превышает 30 символов", nameof(model.Email)); + throw new ArgumentNullException("Нет почты пользователя или длина превышает 40 символов", nameof(model.Email)); } if (!Regex.IsMatch(model.Email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase)) { throw new ArgumentException("Неправильно введенная почта", nameof(model.Email)); } - if (string.IsNullOrEmpty(model.Password) || model.Password.Length > 30 || model.Password.Contains(' ')) + if (string.IsNullOrEmpty(model.Password) || model.Password.Length > 40 || model.Password.Contains(' ')) { throw new ArgumentNullException("Нет пароля пользователя или пароль содержит пробелы", nameof(model.Password)); } diff --git a/HardwareShop/HardwareShopBusinessLogic/HardwareShopBusinessLogic.csproj b/HardwareShop/HardwareShopBusinessLogic/HardwareShopBusinessLogic.csproj index c92001f..b313fbf 100644 --- a/HardwareShop/HardwareShopBusinessLogic/HardwareShopBusinessLogic.csproj +++ b/HardwareShop/HardwareShopBusinessLogic/HardwareShopBusinessLogic.csproj @@ -8,12 +8,14 @@ + + diff --git a/HardwareShop/HardwareShopBusinessLogic/MailWorker/AbstractMailWorker.cs b/HardwareShop/HardwareShopBusinessLogic/MailWorker/AbstractMailWorker.cs new file mode 100644 index 0000000..4fadaf8 --- /dev/null +++ b/HardwareShop/HardwareShopBusinessLogic/MailWorker/AbstractMailWorker.cs @@ -0,0 +1,62 @@ +using HardwareShopContracts.BindingModels; +using Microsoft.Extensions.Logging; + +namespace HardwareShopBusinessLogic.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 ILogger _logger; + + public AbstractMailWorker(ILogger logger) + { + _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); + } + + protected abstract Task SendMailAsync(MailSendInfoBindingModel info); + } +} \ No newline at end of file diff --git a/HardwareShop/HardwareShopBusinessLogic/MailWorker/MailKitWorker.cs b/HardwareShop/HardwareShopBusinessLogic/MailWorker/MailKitWorker.cs new file mode 100644 index 0000000..96a2d20 --- /dev/null +++ b/HardwareShop/HardwareShopBusinessLogic/MailWorker/MailKitWorker.cs @@ -0,0 +1,42 @@ +using HardwareShopContracts.BindingModels; +using HardwareShopContracts.BusinessLogicsContracts; +using MailKit.Net.Pop3; +using MailKit.Security; +using Microsoft.Extensions.Logging; +using System.Net; +using System.Net.Mail; +using System.Text; + +namespace HardwareShopBusinessLogic.MailWorker +{ + public class MailKitWorker : AbstractMailWorker + { + public MailKitWorker(ILogger logger) : base(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; + } + } + } +} \ No newline at end of file diff --git a/HardwareShop/HardwareShopClientApp/Controllers/StorekeeperController.cs b/HardwareShop/HardwareShopClientApp/Controllers/StorekeeperController.cs index bdc6e80..b989862 100644 --- a/HardwareShop/HardwareShopClientApp/Controllers/StorekeeperController.cs +++ b/HardwareShop/HardwareShopClientApp/Controllers/StorekeeperController.cs @@ -431,5 +431,16 @@ namespace HardwareShopStorekeeperApp.Controllers >("api/report/componentsreport", reportModel); return list!; } + + [HttpPost] + public void ReportSendOnMail([FromBody] ReportBindingModel reportModel) + { + if (APIClient.User == null) + { + throw new Exception("Вы как сюда попали? Сюда вход только авторизованным"); + } + reportModel.UserId = APIClient.User.Id; + APIClient.PostRequest("api/report/componentsreportsendonmail", reportModel); + } } } diff --git a/HardwareShop/HardwareShopClientApp/Views/Storekeeper/Report.cshtml b/HardwareShop/HardwareShopClientApp/Views/Storekeeper/Report.cshtml index 44c2ea5..88b75db 100644 --- a/HardwareShop/HardwareShopClientApp/Views/Storekeeper/Report.cshtml +++ b/HardwareShop/HardwareShopClientApp/Views/Storekeeper/Report.cshtml @@ -57,7 +57,18 @@ alert(xhr.responseText); }) } else { alert("empty fields") } + }) + onmail.addEventListener("click" () =>{ + console.log('try to send email') + $.ajax({ + method: "POST", + contentType: "application/json", + url: `/Storekeeper/ReportSendOnMail`, + data: JSON.stringify(reportModel) + }).fail(function(xhr, textStatus, errorThrown) { + alert(xhr.responseText); }) + }) function reloadTable() { resultString = ''; diff --git a/HardwareShop/HardwareShopContracts/BindingModels/MailConfigBindingModel.cs b/HardwareShop/HardwareShopContracts/BindingModels/MailConfigBindingModel.cs new file mode 100644 index 0000000..5eec5f6 --- /dev/null +++ b/HardwareShop/HardwareShopContracts/BindingModels/MailConfigBindingModel.cs @@ -0,0 +1,17 @@ +namespace HardwareShopContracts.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; } + } +} \ No newline at end of file diff --git a/HardwareShop/HardwareShopContracts/BindingModels/MailSendInfoBindingModel.cs b/HardwareShop/HardwareShopContracts/BindingModels/MailSendInfoBindingModel.cs new file mode 100644 index 0000000..11301ec --- /dev/null +++ b/HardwareShop/HardwareShopContracts/BindingModels/MailSendInfoBindingModel.cs @@ -0,0 +1,11 @@ +namespace HardwareShopContracts.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; + } +} \ No newline at end of file diff --git a/HardwareShop/HardwareShopContracts/BindingModels/MessageInfoBindingModel.cs b/HardwareShop/HardwareShopContracts/BindingModels/MessageInfoBindingModel.cs new file mode 100644 index 0000000..dac2eb9 --- /dev/null +++ b/HardwareShop/HardwareShopContracts/BindingModels/MessageInfoBindingModel.cs @@ -0,0 +1,19 @@ +using HardwareShopDataModels.Models; + +namespace HardwareShopContracts.BindingModels +{ + public class MessageInfoBindingModel : IMessageInfoModel + { + public string MessageId { get; set; } = string.Empty; + + public int? UserId { get; set; } + + public string SenderName { get; set; } = string.Empty; + + public string Subject { get; set; } = string.Empty; + + public string Body { get; set; } = string.Empty; + + public DateTime DateDelivery { get; set; } + } +} \ No newline at end of file diff --git a/HardwareShop/HardwareShopContracts/BusinessLogicsContracts/IReportStorekeeperLogic.cs b/HardwareShop/HardwareShopContracts/BusinessLogicsContracts/IReportStorekeeperLogic.cs index f426eb7..bfdcec1 100644 --- a/HardwareShop/HardwareShopContracts/BusinessLogicsContracts/IReportStorekeeperLogic.cs +++ b/HardwareShop/HardwareShopContracts/BusinessLogicsContracts/IReportStorekeeperLogic.cs @@ -31,5 +31,11 @@ namespace HardwareShopContracts.BusinessLogicsContracts /// /// byte[] SaveBuildGoodToExcelFile(ReportBindingModel model, List goods); + + /// + /// Отправление отчета на почту + /// + /// + bool SendReportOnMail(int userId, string subject, string text); } } diff --git a/HardwareShop/HardwareShopDataModels/Models/IMessageInfoModel.cs b/HardwareShop/HardwareShopDataModels/Models/IMessageInfoModel.cs new file mode 100644 index 0000000..06afb02 --- /dev/null +++ b/HardwareShop/HardwareShopDataModels/Models/IMessageInfoModel.cs @@ -0,0 +1,17 @@ +namespace HardwareShopDataModels.Models +{ + public interface IMessageInfoModel + { + string MessageId { get; } + + int? UserId { get; } + + string SenderName { get; } + + DateTime DateDelivery { get; } + + string Subject { get; } + + string Body { get; } + } +} \ No newline at end of file diff --git a/HardwareShop/HardwareShopRestApi/Controllers/ReportController.cs b/HardwareShop/HardwareShopRestApi/Controllers/ReportController.cs index 43b6be8..01a7051 100644 --- a/HardwareShop/HardwareShopRestApi/Controllers/ReportController.cs +++ b/HardwareShop/HardwareShopRestApi/Controllers/ReportController.cs @@ -60,5 +60,19 @@ namespace HardwareShopRestApi.Controllers throw; } } + + [HttpPost] + public void ComponentsReportSendOnMail(ReportBindingModel model) + { + try + { + _reportStorekeeperLogic.SendReportOnMail(model.UserId, "заголовок", "текст"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка получения сведений по полученным пользователем комплектующим за период"); + throw; + } + } } } diff --git a/HardwareShop/HardwareShopRestApi/Program.cs b/HardwareShop/HardwareShopRestApi/Program.cs index 1d68e4b..181d0ca 100644 --- a/HardwareShop/HardwareShopRestApi/Program.cs +++ b/HardwareShop/HardwareShopRestApi/Program.cs @@ -1,7 +1,9 @@ using HardwareShopBusinessLogic.BusinessLogics; using HardwareShopBusinessLogic.BusinessLogics.Storekeeper; +using HardwareShopBusinessLogic.MailWorker; using HardwareShopBusinessLogic.OfficePackage; using HardwareShopBusinessLogic.OfficePackage.Implements; +using HardwareShopContracts.BindingModels; using HardwareShopContracts.BuisnessLogicsContracts; using HardwareShopContracts.BusinessLogicsContracts; using HardwareShopContracts.StoragesContracts; @@ -36,6 +38,8 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); + builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); @@ -46,6 +50,17 @@ builder.Services.AddSwaggerGen(c => 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()) { diff --git a/HardwareShop/HardwareShopRestApi/appsettings.json b/HardwareShop/HardwareShopRestApi/appsettings.json index 10f68b8..6afdb7e 100644 --- a/HardwareShop/HardwareShopRestApi/appsettings.json +++ b/HardwareShop/HardwareShopRestApi/appsettings.json @@ -5,5 +5,12 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + + "SmtpClientHost": "smtp.gmail.com", + "SmtpClientPort": "587", + "PopHost": "pop.gmail.com", + "PopPort": "995", + "MailLogin": "orderbuyerzxc@gmail.com", + "MailPassword": "sjxa uvgn pepe tatl" }