using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Mail; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Services.Notifications; using AsbCloudInfrastructure.Background; using DocumentFormat.OpenXml.Presentation; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace AsbCloudInfrastructure.Services.Email { public class EmailNotificationTransportService : INotificationTransportService { private readonly BackgroundWorker backgroundWorker; private readonly bool IsConfigured; private readonly string sender; private readonly string smtpServer; private readonly string smtpPassword; public EmailNotificationTransportService(BackgroundWorker backgroundWorker, IConfiguration configuration) { sender = configuration.GetValue("email:sender", string.Empty); smtpPassword = configuration.GetValue("email:password", string.Empty); smtpServer = configuration.GetValue("email:smtpServer", string.Empty); var configError = string.IsNullOrEmpty(sender) || string.IsNullOrEmpty(smtpPassword) || string.IsNullOrEmpty(smtpServer); IsConfigured = !configError; this.backgroundWorker = backgroundWorker; } public int IdTransportType => 1; public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken) { if (!IsConfigured) { Trace.TraceWarning("smtp is not configured"); return Task.CompletedTask; } var workId = MakeWorkId(notification.IdUser, notification.Title, notification.Message); if (!backgroundWorker.Works.Any(w=>w.Id==workId)) { var workAction = MakeEmailSendWorkAction(notification); var work = Work.CreateByDelegate(workId, workAction); backgroundWorker.Enqueue(work); } return Task.CompletedTask; } public Task SendRangeAsync(IEnumerable notifications, CancellationToken cancellationToken) { var tasks = notifications .Select(notification => SendAsync(notification, cancellationToken)); return Task.WhenAll(tasks); } private Func, CancellationToken, Task> MakeEmailSendWorkAction(NotificationDto notification) { return async (_, serviceProvider, onProgress, token) => { var notificationRepository = serviceProvider.GetRequiredService(); var userRepository = serviceProvider.GetRequiredService(); var user = await userRepository.GetOrDefaultAsync(notification.IdUser, token) ?? throw new ArgumentInvalidException(nameof(notification.IdUser), "Пользователь не найден"); if(!MailAddress.TryCreate(user.Email, out var mailAddress)) { Trace.TraceWarning($"Mail {user.Email} is not correct."); throw new ArgumentInvalidException(nameof(user.Email), $"Mail {user.Email} is not null."); } var from = new MailAddress(sender); var message = new MailMessage { From = from }; message.To.Add(mailAddress.Address); message.BodyEncoding = System.Text.Encoding.UTF8; message.Body = notification.Message; message.Subject = notification.Title; message.IsBodyHtml = true; using var client = new SmtpClient(smtpServer); client.EnableSsl = true; client.UseDefaultCredentials = false; client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword); await client.SendMailAsync(message, token); notification.SentDate = DateTime.UtcNow; await notificationRepository.UpdateAsync(notification, token); Trace.TraceInformation($"Send email to {user.Email} subj:{notification.Title} html body count {notification.Message.Length}"); }; } private static string MakeWorkId(int idUser, string subject, string content) { var hash = idUser.GetHashCode(); hash ^= subject.GetHashCode(); hash ^= content.GetHashCode(); return hash.ToString("x"); } } }