Отправка уведомлений через email + рефакторинг

1. Адаптировал EmailService под сервис транспорта отправки уведомлений по Email
2. Заменил использование EmailService на NotificationService
3. Поправил тесты
4. Создал запрос для отправки уведомлений
This commit is contained in:
parent 8f76a911a2
commit 4b2d4f1bba
13 changed files with 232 additions and 135 deletions

View File

@ -17,6 +17,11 @@ public class NotificationDto : IId
/// </summary>
public int IdUser { get; set; }
/// <summary>
/// Email получателя уведомления
/// </summary>
public string? UserEmail { get; set; }
/// <summary>
/// Id категории уведомления
/// </summary>
@ -65,6 +70,7 @@ public class NotificationDto : IId
/// <summary>
/// Id типа доставки уведомления
/// 0 - SignalR
/// 1 - Email
/// </summary>
public int IdTransportType { get; set; }

View 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; }
}

View File

@ -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);
}
}

View File

@ -33,35 +33,27 @@ public class NotificationService
this.notificationRepository = notificationRepository;
this.notificationTransportServices = notificationTransportServices;
}
/// <summary>
/// Отправка нового уведомления
/// </summary>
/// <param name="idUser"></param>
/// <param name="idNotificationCategory"></param>
/// <param name="title"></param>
/// <param name="message"></param>
/// <param name="idTransportType"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task NotifyAsync(int idUser,
int idNotificationCategory,
string title,
string message,
int idTransportType,
public async Task NotifyAsync(NotifyRequest request,
CancellationToken cancellationToken)
{
var notificationCategory = await notificationCategoryRepository
.GetOrDefaultAsync(idNotificationCategory, cancellationToken)
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(idNotificationCategory));
.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
var notification = new NotificationDto()
var notification = new NotificationDto
{
IdUser = idUser,
IdNotificationCategory = idNotificationCategory,
Title = title,
Message = message,
IdTransportType = idTransportType
IdUser = request.IdUser,
UserEmail = request.UserEmail,
IdNotificationCategory = request.IdNotificationCategory,
Title = request.Title,
Message = request.Message,
IdTransportType = request.IdTransportType
};
notification.Id = await notificationRepository.InsertAsync(notification,
@ -69,7 +61,7 @@ public class NotificationService
notification.NotificationCategory = notificationCategory;
var notificationTransportService = GetNotificationTransportService(idTransportType);
var notificationTransportService = GetNotificationTransportService(request.IdTransportType);
await notificationTransportService.SendAsync(notification, cancellationToken);

View File

@ -103,7 +103,6 @@ namespace AsbCloudInfrastructure
services.AddMemoryCache();
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>());
services.AddScoped<IEmailService, EmailService>();
services.AddSingleton(new WitsInfoService());
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));

View File

@ -16,6 +16,9 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests;
using AsbCloudApp.Services.Notifications;
using AsbCloudInfrastructure.Services.Email;
namespace AsbCloudInfrastructure.Services.DrillingProgram
{
@ -23,15 +26,18 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
public class DrillingProgramService : IDrillingProgramService
{
private static readonly Dictionary<string, DrillingProgramCreateError> drillingProgramCreateErrors = new Dictionary<string, DrillingProgramCreateError>();
private readonly IAsbCloudDbContext context;
private readonly FileService fileService;
private readonly IUserRepository userRepository;
private readonly IWellService wellService;
private readonly IConfiguration configuration;
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 idFileCategoryDrillingProgramPartsStart = 1001;
private const int idFileCategoryDrillingProgramPartsEnd = 1100;
@ -61,7 +67,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
IWellService wellService,
IConfiguration configuration,
BackgroundWorker backgroundWorker,
IEmailService emailService)
NotificationService notificationService)
{
this.context = context;
this.fileService = fileService;
@ -69,7 +75,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
this.wellService = wellService;
this.configuration = configuration;
this.backgroundWorker = backgroundWorker;
this.emailService = emailService;
this.notificationService = notificationService;
}
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 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)
@ -393,7 +407,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
var subject = factory.MakeSubject(well, "Загруженный вами документ отклонен");
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)
@ -411,7 +433,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
foreach (var user in users)
{
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 subject = factory.MakeSubject(well, $"От вас ожидается загрузка на портал документа «{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)

View File

@ -1,10 +1,7 @@
using AsbCloudApp.Data;
using AsbCloudInfrastructure.Services.Email;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
namespace AsbCloudInfrastructure
namespace AsbCloudInfrastructure.Services.Email
{
class DrillingMailBodyFactory : BaseFactory

View File

@ -1,19 +1,20 @@
using AsbCloudApp.Exceptions;
using AsbCloudApp.Services;
using Microsoft.Extensions.Configuration;
using System;
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.Services.Notifications;
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 bool IsConfigured;
@ -21,7 +22,8 @@ namespace AsbCloudInfrastructure.Services
private readonly string smtpServer;
private readonly string smtpPassword;
public EmailService(BackgroundWorker backgroundWorker, IConfiguration configuration)
public EmailNotificationTransportService(BackgroundWorker backgroundWorker,
IConfiguration configuration)
{
sender = configuration.GetValue("email:sender", string.Empty);
smtpPassword = configuration.GetValue("email:password", string.Empty);
@ -36,25 +38,42 @@ namespace AsbCloudInfrastructure.Services
this.backgroundWorker = backgroundWorker;
}
public void EnqueueSend(string address, string subject, string htmlBody)
=> EnqueueSend(new List<string> { address }, subject, htmlBody);
public void EnqueueSend(IEnumerable<string> addresses, string subject, string htmlBody)
public int IdTransportType => 1;
public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken)
{
if (!IsConfigured)
{
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))
{
var workAction = MakeEmailSendWorkAction(addresses, subject, htmlBody);
var workAction = MakeEmailSendWorkAction(new []{ notification.UserEmail }, notification.Title, notification.Message);
var work = new WorkBase(workId, workAction);
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)
{
var mailAddresses = new List<MailAddress>();

View File

@ -10,6 +10,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Services.Notifications;
namespace AsbCloudInfrastructure.Services
{
@ -23,9 +24,9 @@ namespace AsbCloudInfrastructure.Services
private readonly IUserRepository userRepository;
private readonly IWellService wellService;
private readonly IConfiguration configuration;
private readonly IEmailService emailService;
private readonly IFileCategoryService fileCategoryService;
private readonly IWellFinalDocumentsRepository wellFinalDocumentsRepository;
private readonly NotificationService notificationService;
private const int FileServiceThrewException = -1;
@ -33,17 +34,17 @@ namespace AsbCloudInfrastructure.Services
IUserRepository userRepository,
IWellService wellService,
IConfiguration configuration,
IEmailService emailService,
IFileCategoryService fileCategoryService,
IWellFinalDocumentsRepository wellFinalDocumentsRepository)
IWellFinalDocumentsRepository wellFinalDocumentsRepository,
NotificationService notificationService)
{
this.fileService = fileService;
this.userRepository = userRepository;
this.wellService = wellService;
this.configuration = configuration;
this.emailService = emailService;
this.fileCategoryService = fileCategoryService;
this.wellFinalDocumentsRepository = wellFinalDocumentsRepository;
this.notificationService = notificationService;
}
///<inheritdoc/>
@ -129,27 +130,36 @@ namespace AsbCloudInfrastructure.Services
if(well is null)
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 subject = factory.MakeSubject(well, documentCategory);
if(!string.IsNullOrEmpty(user.Email))
{
var body = factory.MakeMailBodyForWellFinalDocument(
well,
(user.Name ?? user.Surname ?? string.Empty),
string.Format(message, documentCategory)
);
var body = factory.MakeMailBodyForWellFinalDocument(
well,
(user.Name ?? user.Surname ?? string.Empty),
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);
}
}

View File

@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Services.Notifications;
using Xunit;
namespace AsbCloudWebApi.Tests.ServicesTests
@ -85,7 +86,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
private readonly Mock<IWellService> wellServiceMock;
private readonly Mock<IConfiguration> configurationMock;
private readonly Mock<BackgroundWorker> backgroundWorkerMock;
private readonly Mock<IEmailService> emailServiceMock;
private readonly Mock<NotificationService> notificationServiceMock;
public DrillingProgramServiceTest()
{
@ -104,7 +105,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock = new Mock<IWellService>();
configurationMock = new Mock<IConfiguration>();
backgroundWorkerMock = new Mock<BackgroundWorker>();
emailServiceMock = new Mock<IEmailService>();
notificationServiceMock = new Mock<NotificationService>();
}
[Fact]
@ -117,7 +118,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var users = await service.GetAvailableUsers(idWell, CancellationToken.None);
@ -134,7 +135,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var result = await service.AddPartsAsync(idWell, new int[] { 1001, 1002 }, CancellationToken.None);
@ -153,7 +154,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var result = await service.RemovePartsAsync(idWell, new int[] { 1005 }, CancellationToken.None);
@ -176,7 +177,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var result = await service.AddUserAsync(idWell, 1001, publisher1.Id, 1, CancellationToken.None);
@ -211,7 +212,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var result = await service.RemoveUserAsync(idWell, idFileCategory, publisher1.Id, idUserRole, CancellationToken.None);
@ -237,7 +238,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var fileMark = new FileMarkDto
{
@ -268,7 +269,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var fileMark = new FileMarkDto
{
IdFile = file1001.Id,
@ -306,7 +307,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var fileMark = new FileMarkDto
{
@ -333,7 +334,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
@ -360,7 +361,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
@ -390,7 +391,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
wellServiceMock.Object,
configurationMock.Object,
backgroundWorkerMock.Object,
emailServiceMock.Object);
notificationServiceMock.Object);
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);

View File

@ -10,6 +10,7 @@ using System.Linq;
using AsbCloudApp.Repositories;
using System.Collections.Generic;
using AsbCloudApp.Data.User;
using AsbCloudApp.Services.Notifications;
namespace AsbCloudWebApi.Tests.ServicesTests
{
@ -21,8 +22,10 @@ namespace AsbCloudWebApi.Tests.ServicesTests
private readonly WellFinalDocumentsService service;
private readonly Mock<IUserRepository> userRepositoryMock;
private readonly Mock<IWellService> wellServiceMock;
private readonly Mock<IEmailService> emailServiceMock;
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[]{
new UserExtendedDto {
@ -126,7 +129,25 @@ namespace AsbCloudWebApi.Tests.ServicesTests
Deposit = "deposit 1" });
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.Setup(s => s.GetOrDefaultAsync(idWellFinalDocCategory, It.IsAny<CancellationToken>()))
.ReturnsAsync((int id, CancellationToken _) => new FileCategoryDto
@ -140,7 +161,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
userRepository: userRepositoryMock.Object,
wellService: wellServiceMock.Object,
configuration: configuration,
emailService: emailServiceMock.Object,
notificationService: notificationService,
fileCategoryService: fileCategoryService.Object,
wellFinalDocumentsRepository: wellFinalDocumentsRepository.Object);
}
@ -187,13 +208,5 @@ namespace AsbCloudWebApi.Tests.ServicesTests
var data = await service.ReNotifyPublishersAsync(1, users[0].Id, idWellFinalDocCategory, CancellationToken.None);
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>()));
}
}
}

View File

@ -19,12 +19,15 @@ namespace AsbCloudWebApi.Controllers;
[Route("api/notification")]
public class NotificationController : ControllerBase
{
private readonly IUserRepository userRepository;
private readonly NotificationService notificationService;
private readonly INotificationRepository notificationRepository;
public NotificationController(NotificationService notificationService,
public NotificationController(IUserRepository userRepository,
NotificationService notificationService,
INotificationRepository notificationRepository)
{
this.userRepository = userRepository;
this.notificationService = notificationService;
this.notificationRepository = notificationRepository;
}
@ -33,35 +36,40 @@ public class NotificationController : ControllerBase
/// Отправка уведомления
/// </summary>
/// <param name="idUser">Id пользователя</param>
/// <param name="idNotificationCategory">Id категории уведомления. Допустимое значение параметра: 1</param>
/// <param name="idNotificationCategory">Id категории уведомления. Допустимые: 1</param>
/// <param name="title">Заголовок уведомления</param>
/// <param name="message">Сообщение уведомления</param>
/// <param name="idNotificationTransport">Id типа доставки уведомления. Допустимое значение: 0</param>
/// <param name="idTransportType">Id типа доставки уведомления. Допустимые: 0, 1</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost]
[Route("send")]
public async Task<IActionResult> SendAsync([Required] int idUser,
[Required]
[Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
[Required] [Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
int idNotificationCategory,
[Required] string title,
[Required] string message,
[Required]
[Range(minimum: 0, maximum: 0, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0")]
int idNotificationTransport,
[Range(minimum: 0, maximum: 1, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0, 1")]
int idTransportType,
CancellationToken cancellationToken)
{
await notificationService.NotifyAsync(idUser,
idNotificationCategory,
title,
message,
idNotificationTransport,
cancellationToken);
var user = await userRepository.GetOrDefaultAsync(idUser, cancellationToken)
?? throw new ArgumentInvalidException("Пользователь не найден", nameof(idUser));
await notificationService.NotifyAsync(new NotifyRequest
{
IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory,
Title = title,
Message = message,
IdTransportType = idTransportType
}, cancellationToken);
return Ok();
}
/// <summary>
/// Обновление уведомления
/// </summary>
@ -78,10 +86,10 @@ public class NotificationController : ControllerBase
await notificationService.UpdateNotificationAsync(idNotification,
isRead,
cancellationToken);
return Ok();
}
/// <summary>
/// Получение уведомления по Id
/// </summary>
@ -99,12 +107,12 @@ public class NotificationController : ControllerBase
if (notification is null)
{
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(idNotification),
"Уведомление не найдено"));
"Уведомление не найдено"));
}
return Ok(notification);
}
/// <summary>
/// Получение списка уведомлений
/// </summary>
@ -121,7 +129,7 @@ public class NotificationController : ControllerBase
if (!idUser.HasValue)
return Forbid();
var result = await notificationRepository.GetNotificationsAsync(idUser.Value,
request,
cancellationToken);

View File

@ -13,6 +13,7 @@ using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using AsbCloudApp.Services.Notifications;
using AsbCloudInfrastructure.Services.Email;
using AsbCloudWebApi.SignalR.Services;
using Microsoft.OpenApi.Any;
@ -139,6 +140,7 @@ namespace AsbCloudWebApi
public static void AddNotificationTransportServices(this IServiceCollection services)
{
services.AddTransient<INotificationTransportService, SignalRNotificationTransportService>();
services.AddTransient<INotificationTransportService, EmailNotificationTransportService>();
}
}
}