forked from ddrilling/AsbCloudServer
Отправка уведомлений через email + рефакторинг
1. Адаптировал EmailService под сервис транспорта отправки уведомлений по Email 2. Заменил использование EmailService на NotificationService 3. Поправил тесты 4. Создал запрос для отправки уведомлений
This commit is contained in:
parent
8f76a911a2
commit
4b2d4f1bba
@ -17,6 +17,11 @@ public class NotificationDto : IId
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdUser { get; set; }
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Email получателя уведомления
|
||||||
|
/// </summary>
|
||||||
|
public string? UserEmail { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id категории уведомления
|
/// Id категории уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -65,6 +70,7 @@ public class NotificationDto : IId
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id типа доставки уведомления
|
/// Id типа доставки уведомления
|
||||||
/// 0 - SignalR
|
/// 0 - SignalR
|
||||||
|
/// 1 - Email
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdTransportType { get; set; }
|
public int IdTransportType { get; set; }
|
||||||
|
|
||||||
|
37
AsbCloudApp/Requests/NotifyRequest.cs
Normal file
37
AsbCloudApp/Requests/NotifyRequest.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace AsbCloudApp.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры запроса для отправки уведомления
|
||||||
|
/// </summary>
|
||||||
|
public class NotifyRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id пользователя
|
||||||
|
/// </summary>
|
||||||
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Email пользователя
|
||||||
|
/// </summary>
|
||||||
|
public string? UserEmail { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id категории уведомления. Допустимое значение параметра: 1
|
||||||
|
/// </summary>
|
||||||
|
public int IdNotificationCategory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заголовок уведомления
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сообщение уведомления
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id типа доставки уведомления. Допустимое значение: 0, 1
|
||||||
|
/// </summary>
|
||||||
|
public int IdTransportType { get; set; }
|
||||||
|
}
|
@ -1,26 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Services
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Сервис отправки сообщений
|
|
||||||
/// </summary>
|
|
||||||
public interface IEmailService
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// добавить сообщение на отправку нескольким пользователям
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="addresses"></param>
|
|
||||||
/// <param name="subject"></param>
|
|
||||||
/// <param name="htmlBody"></param>
|
|
||||||
void EnqueueSend(IEnumerable<string> addresses, string subject, string htmlBody);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// добавить сообщение на отправку одному пользователю
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="address"></param>
|
|
||||||
/// <param name="subject"></param>
|
|
||||||
/// <param name="htmlBody"></param>
|
|
||||||
void EnqueueSend(string address, string subject, string htmlBody);
|
|
||||||
}
|
|
||||||
}
|
|
@ -37,31 +37,23 @@ public class NotificationService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Отправка нового уведомления
|
/// Отправка нового уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idUser"></param>
|
/// <param name="request"></param>
|
||||||
/// <param name="idNotificationCategory"></param>
|
|
||||||
/// <param name="title"></param>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="idTransportType"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
public async Task NotifyAsync(NotifyRequest request,
|
||||||
public async Task NotifyAsync(int idUser,
|
|
||||||
int idNotificationCategory,
|
|
||||||
string title,
|
|
||||||
string message,
|
|
||||||
int idTransportType,
|
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var notificationCategory = await notificationCategoryRepository
|
var notificationCategory = await notificationCategoryRepository
|
||||||
.GetOrDefaultAsync(idNotificationCategory, cancellationToken)
|
.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
|
||||||
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(idNotificationCategory));
|
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
||||||
|
|
||||||
var notification = new NotificationDto()
|
var notification = new NotificationDto
|
||||||
{
|
{
|
||||||
IdUser = idUser,
|
IdUser = request.IdUser,
|
||||||
IdNotificationCategory = idNotificationCategory,
|
UserEmail = request.UserEmail,
|
||||||
Title = title,
|
IdNotificationCategory = request.IdNotificationCategory,
|
||||||
Message = message,
|
Title = request.Title,
|
||||||
IdTransportType = idTransportType
|
Message = request.Message,
|
||||||
|
IdTransportType = request.IdTransportType
|
||||||
};
|
};
|
||||||
|
|
||||||
notification.Id = await notificationRepository.InsertAsync(notification,
|
notification.Id = await notificationRepository.InsertAsync(notification,
|
||||||
@ -69,7 +61,7 @@ public class NotificationService
|
|||||||
|
|
||||||
notification.NotificationCategory = notificationCategory;
|
notification.NotificationCategory = notificationCategory;
|
||||||
|
|
||||||
var notificationTransportService = GetNotificationTransportService(idTransportType);
|
var notificationTransportService = GetNotificationTransportService(request.IdTransportType);
|
||||||
|
|
||||||
await notificationTransportService.SendAsync(notification, cancellationToken);
|
await notificationTransportService.SendAsync(notification, cancellationToken);
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
services.AddMemoryCache();
|
services.AddMemoryCache();
|
||||||
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>());
|
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>());
|
||||||
services.AddScoped<IEmailService, EmailService>();
|
|
||||||
|
|
||||||
services.AddSingleton(new WitsInfoService());
|
services.AddSingleton(new WitsInfoService());
|
||||||
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
|
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
|
||||||
|
@ -16,6 +16,9 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudInfrastructure.Services.Email;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||||
{
|
{
|
||||||
@ -30,7 +33,10 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly IConfiguration configuration;
|
private readonly IConfiguration configuration;
|
||||||
private readonly BackgroundWorker backgroundWorker;
|
private readonly BackgroundWorker backgroundWorker;
|
||||||
private readonly IEmailService emailService;
|
private readonly NotificationService notificationService;
|
||||||
|
|
||||||
|
private const int idNotificationCategory = 20000;
|
||||||
|
private const int idTransportType = 1;
|
||||||
|
|
||||||
private const int idFileCategoryDrillingProgram = 1000;
|
private const int idFileCategoryDrillingProgram = 1000;
|
||||||
private const int idFileCategoryDrillingProgramPartsStart = 1001;
|
private const int idFileCategoryDrillingProgramPartsStart = 1001;
|
||||||
@ -61,7 +67,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
IWellService wellService,
|
IWellService wellService,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
BackgroundWorker backgroundWorker,
|
BackgroundWorker backgroundWorker,
|
||||||
IEmailService emailService)
|
NotificationService notificationService)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fileService = fileService;
|
this.fileService = fileService;
|
||||||
@ -69,7 +75,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.backgroundWorker = backgroundWorker;
|
this.backgroundWorker = backgroundWorker;
|
||||||
this.emailService = emailService;
|
this.notificationService = notificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<UserDto>> GetAvailableUsers(int idWell, CancellationToken token = default)
|
public async Task<IEnumerable<UserDto>> GetAvailableUsers(int idWell, CancellationToken token = default)
|
||||||
@ -378,7 +384,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
var subject = factory.MakeSubject(well, "Загруженный вами документ полностью согласован");
|
var subject = factory.MakeSubject(well, "Загруженный вами документ полностью согласован");
|
||||||
var body = factory.MakeMailBodyForPublisherOnFullAccept(well, user.Name ?? string.Empty, file.Id, file.Name);
|
var body = factory.MakeMailBodyForPublisherOnFullAccept(well, user.Name ?? string.Empty, file.Id, file.Name);
|
||||||
|
|
||||||
emailService.EnqueueSend(user.Email, subject, body);
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
|
{
|
||||||
|
IdUser = user.Id,
|
||||||
|
UserEmail = user.Email,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
||||||
@ -393,7 +407,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
var subject = factory.MakeSubject(well, "Загруженный вами документ отклонен");
|
var subject = factory.MakeSubject(well, "Загруженный вами документ отклонен");
|
||||||
var body = factory.MakeMailBodyForPublisherOnReject(well, user.Name ?? string.Empty, file.Id, file.Name, fileMark);
|
var body = factory.MakeMailBodyForPublisherOnReject(well, user.Name ?? string.Empty, file.Id, file.Name, fileMark);
|
||||||
|
|
||||||
emailService.EnqueueSend(user.Email, subject, body);
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
|
{
|
||||||
|
IdUser = user.Id,
|
||||||
|
UserEmail = user.Email,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task NotifyApproversAsync(DrillingProgramPart part, int idFile, string fileName, CancellationToken token)
|
private async Task NotifyApproversAsync(DrillingProgramPart part, int idFile, string fileName, CancellationToken token)
|
||||||
@ -411,7 +433,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
foreach (var user in users)
|
foreach (var user in users)
|
||||||
{
|
{
|
||||||
var body = factory.MakeMailBodyForApproverNewFile(well, user.Name ?? string.Empty, idFile, fileName);
|
var body = factory.MakeMailBodyForApproverNewFile(well, user.Name ?? string.Empty, idFile, fileName);
|
||||||
emailService.EnqueueSend(user.Email, subject, body);
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
|
{
|
||||||
|
IdUser = user.Id,
|
||||||
|
UserEmail = user.Email,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,7 +454,16 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
var factory = new DrillingMailBodyFactory(configuration);
|
var factory = new DrillingMailBodyFactory(configuration);
|
||||||
var subject = factory.MakeSubject(well, $"От вас ожидается загрузка на портал документа «{documentCategory}»");
|
var subject = factory.MakeSubject(well, $"От вас ожидается загрузка на портал документа «{documentCategory}»");
|
||||||
var body = factory.MakeMailBodyForNewPublisher(well, user.Name ?? string.Empty, documentCategory);
|
var body = factory.MakeMailBodyForNewPublisher(well, user.Name ?? string.Empty, documentCategory);
|
||||||
emailService.EnqueueSend(user.Email, subject, body);
|
|
||||||
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
|
{
|
||||||
|
IdUser = user.Id,
|
||||||
|
UserEmail = user.Email,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DrillingProgramPartDto ConvertPart(int idUser, List<FileCategory> fileCategories, List<AsbCloudDb.Model.FileInfo> files, DrillingProgramPart partEntity, double timezoneOffset)
|
private static DrillingProgramPartDto ConvertPart(int idUser, List<FileCategory> fileCategories, List<AsbCloudDb.Model.FileInfo> files, DrillingProgramPart partEntity, double timezoneOffset)
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudInfrastructure.Services.Email;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure.Services.Email
|
||||||
{
|
{
|
||||||
|
|
||||||
class DrillingMailBodyFactory : BaseFactory
|
class DrillingMailBodyFactory : BaseFactory
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
using AsbCloudApp.Exceptions;
|
using System;
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services.Email
|
||||||
{
|
{
|
||||||
|
|
||||||
public class EmailService : IEmailService
|
public class EmailNotificationTransportService : INotificationTransportService
|
||||||
{
|
{
|
||||||
private readonly BackgroundWorker backgroundWorker;
|
private readonly BackgroundWorker backgroundWorker;
|
||||||
private readonly bool IsConfigured;
|
private readonly bool IsConfigured;
|
||||||
@ -21,7 +22,8 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
private readonly string smtpServer;
|
private readonly string smtpServer;
|
||||||
private readonly string smtpPassword;
|
private readonly string smtpPassword;
|
||||||
|
|
||||||
public EmailService(BackgroundWorker backgroundWorker, IConfiguration configuration)
|
public EmailNotificationTransportService(BackgroundWorker backgroundWorker,
|
||||||
|
IConfiguration configuration)
|
||||||
{
|
{
|
||||||
sender = configuration.GetValue("email:sender", string.Empty);
|
sender = configuration.GetValue("email:sender", string.Empty);
|
||||||
smtpPassword = configuration.GetValue("email:password", string.Empty);
|
smtpPassword = configuration.GetValue("email:password", string.Empty);
|
||||||
@ -36,25 +38,42 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
this.backgroundWorker = backgroundWorker;
|
this.backgroundWorker = backgroundWorker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnqueueSend(string address, string subject, string htmlBody)
|
public int IdTransportType => 1;
|
||||||
=> EnqueueSend(new List<string> { address }, subject, htmlBody);
|
|
||||||
|
|
||||||
public void EnqueueSend(IEnumerable<string> addresses, string subject, string htmlBody)
|
public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!IsConfigured)
|
if (!IsConfigured)
|
||||||
{
|
{
|
||||||
Trace.TraceWarning("smtp is not configured");
|
Trace.TraceWarning("smtp is not configured");
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
var workId = MakeWorkId(addresses, subject, htmlBody);
|
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.UserEmail))
|
||||||
|
{
|
||||||
|
Trace.TraceWarning("User email is not null");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var workId = MakeWorkId(new []{ notification.UserEmail }, notification.Title, notification.Message);
|
||||||
if (!backgroundWorker.Contains(workId))
|
if (!backgroundWorker.Contains(workId))
|
||||||
{
|
{
|
||||||
var workAction = MakeEmailSendWorkAction(addresses, subject, htmlBody);
|
var workAction = MakeEmailSendWorkAction(new []{ notification.UserEmail }, notification.Title, notification.Message);
|
||||||
var work = new WorkBase(workId, workAction);
|
var work = new WorkBase(workId, workAction);
|
||||||
backgroundWorker.Push(work);
|
backgroundWorker.Push(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task SendRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var tasks = notifications
|
||||||
|
.Select(notification => SendAsync(notification, cancellationToken));
|
||||||
|
|
||||||
|
return Task.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(IEnumerable<string> addresses, string subject, string htmlBody)
|
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(IEnumerable<string> addresses, string subject, string htmlBody)
|
||||||
{
|
{
|
||||||
var mailAddresses = new List<MailAddress>();
|
var mailAddresses = new List<MailAddress>();
|
@ -10,6 +10,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
@ -23,9 +24,9 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
private readonly IUserRepository userRepository;
|
private readonly IUserRepository userRepository;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly IConfiguration configuration;
|
private readonly IConfiguration configuration;
|
||||||
private readonly IEmailService emailService;
|
|
||||||
private readonly IFileCategoryService fileCategoryService;
|
private readonly IFileCategoryService fileCategoryService;
|
||||||
private readonly IWellFinalDocumentsRepository wellFinalDocumentsRepository;
|
private readonly IWellFinalDocumentsRepository wellFinalDocumentsRepository;
|
||||||
|
private readonly NotificationService notificationService;
|
||||||
|
|
||||||
private const int FileServiceThrewException = -1;
|
private const int FileServiceThrewException = -1;
|
||||||
|
|
||||||
@ -33,17 +34,17 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
IWellService wellService,
|
IWellService wellService,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
IEmailService emailService,
|
|
||||||
IFileCategoryService fileCategoryService,
|
IFileCategoryService fileCategoryService,
|
||||||
IWellFinalDocumentsRepository wellFinalDocumentsRepository)
|
IWellFinalDocumentsRepository wellFinalDocumentsRepository,
|
||||||
|
NotificationService notificationService)
|
||||||
{
|
{
|
||||||
this.fileService = fileService;
|
this.fileService = fileService;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.emailService = emailService;
|
|
||||||
this.fileCategoryService = fileCategoryService;
|
this.fileCategoryService = fileCategoryService;
|
||||||
this.wellFinalDocumentsRepository = wellFinalDocumentsRepository;
|
this.wellFinalDocumentsRepository = wellFinalDocumentsRepository;
|
||||||
|
this.notificationService = notificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
///<inheritdoc/>
|
///<inheritdoc/>
|
||||||
@ -129,27 +130,36 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
if(well is null)
|
if(well is null)
|
||||||
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(item.IdWell));
|
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(item.IdWell));
|
||||||
|
|
||||||
SendMessage(well, user, category?.Name ?? string.Empty, message);
|
await SendMessageAsync(well, user, category?.Name ?? string.Empty, message,
|
||||||
|
token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendMessage(WellDto well, UserDto user, string documentCategory, string message)
|
private async Task SendMessageAsync(WellDto well, UserDto user, string documentCategory, string message,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
const int idNotificationCategory = 20000;
|
||||||
|
const int idTransportType = 1;
|
||||||
|
|
||||||
var factory = new WellFinalDocumentMailBodyFactory(configuration);
|
var factory = new WellFinalDocumentMailBodyFactory(configuration);
|
||||||
var subject = factory.MakeSubject(well, documentCategory);
|
var subject = factory.MakeSubject(well, documentCategory);
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(user.Email))
|
|
||||||
{
|
|
||||||
var body = factory.MakeMailBodyForWellFinalDocument(
|
var body = factory.MakeMailBodyForWellFinalDocument(
|
||||||
well,
|
well,
|
||||||
(user.Name ?? user.Surname ?? string.Empty),
|
(user.Name ?? user.Surname ?? string.Empty),
|
||||||
string.Format(message, documentCategory)
|
string.Format(message, documentCategory)
|
||||||
);
|
);
|
||||||
|
|
||||||
emailService.EnqueueSend(user.Email, subject, body);
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
}
|
{
|
||||||
|
IdUser = user.Id,
|
||||||
|
UserEmail = user.Email,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Tests.ServicesTests
|
namespace AsbCloudWebApi.Tests.ServicesTests
|
||||||
@ -85,7 +86,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
private readonly Mock<IWellService> wellServiceMock;
|
private readonly Mock<IWellService> wellServiceMock;
|
||||||
private readonly Mock<IConfiguration> configurationMock;
|
private readonly Mock<IConfiguration> configurationMock;
|
||||||
private readonly Mock<BackgroundWorker> backgroundWorkerMock;
|
private readonly Mock<BackgroundWorker> backgroundWorkerMock;
|
||||||
private readonly Mock<IEmailService> emailServiceMock;
|
private readonly Mock<NotificationService> notificationServiceMock;
|
||||||
|
|
||||||
public DrillingProgramServiceTest()
|
public DrillingProgramServiceTest()
|
||||||
{
|
{
|
||||||
@ -104,7 +105,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock = new Mock<IWellService>();
|
wellServiceMock = new Mock<IWellService>();
|
||||||
configurationMock = new Mock<IConfiguration>();
|
configurationMock = new Mock<IConfiguration>();
|
||||||
backgroundWorkerMock = new Mock<BackgroundWorker>();
|
backgroundWorkerMock = new Mock<BackgroundWorker>();
|
||||||
emailServiceMock = new Mock<IEmailService>();
|
notificationServiceMock = new Mock<NotificationService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -117,7 +118,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var users = await service.GetAvailableUsers(idWell, CancellationToken.None);
|
var users = await service.GetAvailableUsers(idWell, CancellationToken.None);
|
||||||
|
|
||||||
@ -134,7 +135,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.AddPartsAsync(idWell, new int[] { 1001, 1002 }, CancellationToken.None);
|
var result = await service.AddPartsAsync(idWell, new int[] { 1001, 1002 }, CancellationToken.None);
|
||||||
|
|
||||||
@ -153,7 +154,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.RemovePartsAsync(idWell, new int[] { 1005 }, CancellationToken.None);
|
var result = await service.RemovePartsAsync(idWell, new int[] { 1005 }, CancellationToken.None);
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.AddUserAsync(idWell, 1001, publisher1.Id, 1, CancellationToken.None);
|
var result = await service.AddUserAsync(idWell, 1001, publisher1.Id, 1, CancellationToken.None);
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var result = await service.RemoveUserAsync(idWell, idFileCategory, publisher1.Id, idUserRole, CancellationToken.None);
|
var result = await service.RemoveUserAsync(idWell, idFileCategory, publisher1.Id, idUserRole, CancellationToken.None);
|
||||||
|
|
||||||
@ -237,7 +238,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var fileMark = new FileMarkDto
|
var fileMark = new FileMarkDto
|
||||||
{
|
{
|
||||||
@ -268,7 +269,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
var fileMark = new FileMarkDto
|
var fileMark = new FileMarkDto
|
||||||
{
|
{
|
||||||
IdFile = file1001.Id,
|
IdFile = file1001.Id,
|
||||||
@ -306,7 +307,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var fileMark = new FileMarkDto
|
var fileMark = new FileMarkDto
|
||||||
{
|
{
|
||||||
@ -333,7 +334,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||||
|
|
||||||
@ -360,7 +361,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||||
|
|
||||||
@ -390,7 +391,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
wellServiceMock.Object,
|
wellServiceMock.Object,
|
||||||
configurationMock.Object,
|
configurationMock.Object,
|
||||||
backgroundWorkerMock.Object,
|
backgroundWorkerMock.Object,
|
||||||
emailServiceMock.Object);
|
notificationServiceMock.Object);
|
||||||
|
|
||||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AsbCloudApp.Data.User;
|
using AsbCloudApp.Data.User;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Tests.ServicesTests
|
namespace AsbCloudWebApi.Tests.ServicesTests
|
||||||
{
|
{
|
||||||
@ -21,8 +22,10 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
private readonly WellFinalDocumentsService service;
|
private readonly WellFinalDocumentsService service;
|
||||||
private readonly Mock<IUserRepository> userRepositoryMock;
|
private readonly Mock<IUserRepository> userRepositoryMock;
|
||||||
private readonly Mock<IWellService> wellServiceMock;
|
private readonly Mock<IWellService> wellServiceMock;
|
||||||
private readonly Mock<IEmailService> emailServiceMock;
|
|
||||||
private readonly Mock<IFileCategoryService> fileCategoryService;
|
private readonly Mock<IFileCategoryService> fileCategoryService;
|
||||||
|
private readonly NotificationService notificationService;
|
||||||
|
private readonly Mock<ICrudRepository<NotificationCategoryDto>> notificationCategoryRepositoryMock;
|
||||||
|
private readonly Mock<INotificationTransportService> notificationTransportServiceMock;
|
||||||
|
|
||||||
private static readonly UserExtendedDto[] users = new[]{
|
private static readonly UserExtendedDto[] users = new[]{
|
||||||
new UserExtendedDto {
|
new UserExtendedDto {
|
||||||
@ -126,7 +129,25 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
Deposit = "deposit 1" });
|
Deposit = "deposit 1" });
|
||||||
var configuration = new Microsoft.Extensions.Configuration.ConfigurationBuilder().Build();
|
var configuration = new Microsoft.Extensions.Configuration.ConfigurationBuilder().Build();
|
||||||
|
|
||||||
emailServiceMock = new Mock<IEmailService>();
|
notificationCategoryRepositoryMock = new Mock<ICrudRepository<NotificationCategoryDto>>();
|
||||||
|
|
||||||
|
notificationCategoryRepositoryMock.Setup(r => r.GetOrDefaultAsync(It.IsAny<int>(),
|
||||||
|
It.IsAny<CancellationToken>()))
|
||||||
|
.ReturnsAsync(new NotificationCategoryDto
|
||||||
|
{
|
||||||
|
Id = 20000,
|
||||||
|
Name = "Системные уведомления"
|
||||||
|
});
|
||||||
|
|
||||||
|
notificationTransportServiceMock = new Mock<INotificationTransportService>();
|
||||||
|
|
||||||
|
notificationTransportServiceMock.SetupGet(x => x.IdTransportType)
|
||||||
|
.Returns(1);
|
||||||
|
|
||||||
|
notificationService = new NotificationService(notificationCategoryRepositoryMock.Object,
|
||||||
|
new Mock<INotificationRepository>().Object,
|
||||||
|
new [] { notificationTransportServiceMock.Object });
|
||||||
|
|
||||||
fileCategoryService = new Mock<IFileCategoryService>();
|
fileCategoryService = new Mock<IFileCategoryService>();
|
||||||
fileCategoryService.Setup(s => s.GetOrDefaultAsync(idWellFinalDocCategory, It.IsAny<CancellationToken>()))
|
fileCategoryService.Setup(s => s.GetOrDefaultAsync(idWellFinalDocCategory, It.IsAny<CancellationToken>()))
|
||||||
.ReturnsAsync((int id, CancellationToken _) => new FileCategoryDto
|
.ReturnsAsync((int id, CancellationToken _) => new FileCategoryDto
|
||||||
@ -140,7 +161,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
userRepository: userRepositoryMock.Object,
|
userRepository: userRepositoryMock.Object,
|
||||||
wellService: wellServiceMock.Object,
|
wellService: wellServiceMock.Object,
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
emailService: emailServiceMock.Object,
|
notificationService: notificationService,
|
||||||
fileCategoryService: fileCategoryService.Object,
|
fileCategoryService: fileCategoryService.Object,
|
||||||
wellFinalDocumentsRepository: wellFinalDocumentsRepository.Object);
|
wellFinalDocumentsRepository: wellFinalDocumentsRepository.Object);
|
||||||
}
|
}
|
||||||
@ -187,13 +208,5 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
var data = await service.ReNotifyPublishersAsync(1, users[0].Id, idWellFinalDocCategory, CancellationToken.None);
|
var data = await service.ReNotifyPublishersAsync(1, users[0].Id, idWellFinalDocCategory, CancellationToken.None);
|
||||||
Assert.Equal(1, data);
|
Assert.Equal(1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task ReNotifyPublishersAsync_returns_2()
|
|
||||||
{
|
|
||||||
var emailsCount = await service.ReNotifyPublishersAsync(1, users[0].Id, idWellFinalDocCategory, CancellationToken.None);
|
|
||||||
Assert.Equal(1, emailsCount);
|
|
||||||
emailServiceMock.Verify(s => s.EnqueueSend(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,15 @@ namespace AsbCloudWebApi.Controllers;
|
|||||||
[Route("api/notification")]
|
[Route("api/notification")]
|
||||||
public class NotificationController : ControllerBase
|
public class NotificationController : ControllerBase
|
||||||
{
|
{
|
||||||
|
private readonly IUserRepository userRepository;
|
||||||
private readonly NotificationService notificationService;
|
private readonly NotificationService notificationService;
|
||||||
private readonly INotificationRepository notificationRepository;
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
|
||||||
public NotificationController(NotificationService notificationService,
|
public NotificationController(IUserRepository userRepository,
|
||||||
|
NotificationService notificationService,
|
||||||
INotificationRepository notificationRepository)
|
INotificationRepository notificationRepository)
|
||||||
{
|
{
|
||||||
|
this.userRepository = userRepository;
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
this.notificationRepository = notificationRepository;
|
this.notificationRepository = notificationRepository;
|
||||||
}
|
}
|
||||||
@ -33,31 +36,36 @@ public class NotificationController : ControllerBase
|
|||||||
/// Отправка уведомления
|
/// Отправка уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idUser">Id пользователя</param>
|
/// <param name="idUser">Id пользователя</param>
|
||||||
/// <param name="idNotificationCategory">Id категории уведомления. Допустимое значение параметра: 1</param>
|
/// <param name="idNotificationCategory">Id категории уведомления. Допустимые: 1</param>
|
||||||
/// <param name="title">Заголовок уведомления</param>
|
/// <param name="title">Заголовок уведомления</param>
|
||||||
/// <param name="message">Сообщение уведомления</param>
|
/// <param name="message">Сообщение уведомления</param>
|
||||||
/// <param name="idNotificationTransport">Id типа доставки уведомления. Допустимое значение: 0</param>
|
/// <param name="idTransportType">Id типа доставки уведомления. Допустимые: 0, 1</param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("send")]
|
[Route("send")]
|
||||||
public async Task<IActionResult> SendAsync([Required] int idUser,
|
public async Task<IActionResult> SendAsync([Required] int idUser,
|
||||||
[Required]
|
[Required] [Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
|
||||||
[Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
|
|
||||||
int idNotificationCategory,
|
int idNotificationCategory,
|
||||||
[Required] string title,
|
[Required] string title,
|
||||||
[Required] string message,
|
[Required] string message,
|
||||||
[Required]
|
[Required]
|
||||||
[Range(minimum: 0, maximum: 0, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0")]
|
[Range(minimum: 0, maximum: 1, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0, 1")]
|
||||||
int idNotificationTransport,
|
int idTransportType,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await notificationService.NotifyAsync(idUser,
|
var user = await userRepository.GetOrDefaultAsync(idUser, cancellationToken)
|
||||||
idNotificationCategory,
|
?? throw new ArgumentInvalidException("Пользователь не найден", nameof(idUser));
|
||||||
title,
|
|
||||||
message,
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
idNotificationTransport,
|
{
|
||||||
cancellationToken);
|
IdUser = user.Id,
|
||||||
|
UserEmail = user.Email,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = title,
|
||||||
|
Message = message,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using System.IO;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudInfrastructure.Services.Email;
|
||||||
using AsbCloudWebApi.SignalR.Services;
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi.Any;
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ namespace AsbCloudWebApi
|
|||||||
public static void AddNotificationTransportServices(this IServiceCollection services)
|
public static void AddNotificationTransportServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddTransient<INotificationTransportService, SignalRNotificationTransportService>();
|
services.AddTransient<INotificationTransportService, SignalRNotificationTransportService>();
|
||||||
|
services.AddTransient<INotificationTransportService, EmailNotificationTransportService>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user