forked from ddrilling/AsbCloudServer
Изменение уведомлений
1. Изменил сущность уведомлений. Добавил дату регистрации уведомления. 2. Добавил миграцию. 3. Изменил репозитории. Убрал метод для обновления коллекции уведомлений. 4. Поправил запрос для отправки уведомлений и метод контроллера. 5. Поправил логику обновления уведомления. Теперь обновление состояния уведомления происходит в транспорте, после успешной отправки уведомления.
This commit is contained in:
parent
1639e9c153
commit
1b560dd0a2
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using AsbCloudApp.Data.User;
|
||||||
|
|
||||||
namespace AsbCloudApp.Data;
|
namespace AsbCloudApp.Data;
|
||||||
|
|
||||||
@ -17,11 +18,6 @@ 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>
|
||||||
@ -37,6 +33,11 @@ public class NotificationDto : IId
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Message { get; set; } = null!;
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата регистрации уведомления
|
||||||
|
/// </summary>
|
||||||
|
public DateTime RegistrationDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата отправки уведомления
|
/// Дата отправки уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -78,4 +79,9 @@ public class NotificationDto : IId
|
|||||||
/// DTO категории уведомления
|
/// DTO категории уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NotificationCategoryDto NotificationCategory { get; set; } = null!;
|
public NotificationCategoryDto NotificationCategory { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DTO получателя уведомления
|
||||||
|
/// </summary>
|
||||||
|
public UserDto User { get; set; } = null!;
|
||||||
}
|
}
|
@ -1,4 +1,3 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
@ -12,15 +11,6 @@ namespace AsbCloudApp.Repositories;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface INotificationRepository : ICrudRepository<NotificationDto>
|
public interface INotificationRepository : ICrudRepository<NotificationDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Обновление изменённых уведомлений
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="notifications"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications,
|
|
||||||
CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение уведомлений по параметрам
|
/// Получение уведомлений по параметрам
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace AsbCloudApp.Requests;
|
namespace AsbCloudApp.Requests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -6,32 +8,34 @@ namespace AsbCloudApp.Requests;
|
|||||||
public class NotifyRequest
|
public class NotifyRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id пользователя
|
/// Id получателя уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public int IdUser { get; set; }
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Email пользователя
|
|
||||||
/// </summary>
|
|
||||||
public string? UserEmail { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id категории уведомления. Допустимое значение параметра: 1
|
/// Id категории уведомления. Допустимое значение параметра: 1
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
[Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
|
||||||
public int IdNotificationCategory { get; set; }
|
public int IdNotificationCategory { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Заголовок уведомления
|
/// Заголовок уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public string Title { get; set; } = null!;
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сообщение уведомления
|
/// Сообщение уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public string Message { get; set; } = null!;
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id типа доставки уведомления. Допустимое значение: 0, 1
|
/// Id типа доставки уведомления. Допустимое значение: 0, 1
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
[Range(minimum: 0, maximum: 1, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0, 1")]
|
||||||
public int IdTransportType { get; set; }
|
public int IdTransportType { get; set; }
|
||||||
}
|
}
|
@ -16,6 +16,7 @@ namespace AsbCloudApp.Services.Notifications;
|
|||||||
public class NotificationService
|
public class NotificationService
|
||||||
{
|
{
|
||||||
private readonly ICrudRepository<NotificationCategoryDto> notificationCategoryRepository;
|
private readonly ICrudRepository<NotificationCategoryDto> notificationCategoryRepository;
|
||||||
|
private readonly IUserRepository userRepository;
|
||||||
private readonly INotificationRepository notificationRepository;
|
private readonly INotificationRepository notificationRepository;
|
||||||
private readonly IEnumerable<INotificationTransportService> notificationTransportServices;
|
private readonly IEnumerable<INotificationTransportService> notificationTransportServices;
|
||||||
|
|
||||||
@ -23,12 +24,15 @@ public class NotificationService
|
|||||||
/// Сервис для работы с уведомлениями
|
/// Сервис для работы с уведомлениями
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="notificationCategoryRepository"></param>
|
/// <param name="notificationCategoryRepository"></param>
|
||||||
|
/// <param name="userRepository"></param>
|
||||||
/// <param name="notificationRepository"></param>
|
/// <param name="notificationRepository"></param>
|
||||||
/// <param name="notificationTransportServices"></param>
|
/// <param name="notificationTransportServices"></param>
|
||||||
public NotificationService(ICrudRepository<NotificationCategoryDto> notificationCategoryRepository,
|
public NotificationService(ICrudRepository<NotificationCategoryDto> notificationCategoryRepository,
|
||||||
|
IUserRepository userRepository,
|
||||||
INotificationRepository notificationRepository,
|
INotificationRepository notificationRepository,
|
||||||
IEnumerable<INotificationTransportService> notificationTransportServices)
|
IEnumerable<INotificationTransportService> notificationTransportServices)
|
||||||
{
|
{
|
||||||
|
this.userRepository = userRepository;
|
||||||
this.notificationCategoryRepository = notificationCategoryRepository;
|
this.notificationCategoryRepository = notificationCategoryRepository;
|
||||||
this.notificationRepository = notificationRepository;
|
this.notificationRepository = notificationRepository;
|
||||||
this.notificationTransportServices = notificationTransportServices;
|
this.notificationTransportServices = notificationTransportServices;
|
||||||
@ -46,27 +50,26 @@ public class NotificationService
|
|||||||
.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
|
.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
|
||||||
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
||||||
|
|
||||||
|
var user = await userRepository.GetOrDefaultAsync(request.IdUser, cancellationToken)
|
||||||
|
?? throw new ArgumentInvalidException("Пользователь не найден" , nameof(request.IdUser));
|
||||||
|
|
||||||
var notification = new NotificationDto
|
var notification = new NotificationDto
|
||||||
{
|
{
|
||||||
IdUser = request.IdUser,
|
IdUser = request.IdUser,
|
||||||
UserEmail = request.UserEmail,
|
RegistrationDate = DateTime.UtcNow,
|
||||||
IdNotificationCategory = request.IdNotificationCategory,
|
IdNotificationCategory = request.IdNotificationCategory,
|
||||||
Title = request.Title,
|
Title = request.Title,
|
||||||
Message = request.Message,
|
Message = request.Message,
|
||||||
IdTransportType = request.IdTransportType
|
IdTransportType = request.IdTransportType,
|
||||||
};
|
};
|
||||||
|
|
||||||
notification.Id = await notificationRepository.InsertAsync(notification,
|
notification.Id = await notificationRepository.InsertAsync(notification, cancellationToken);
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
notification.NotificationCategory = notificationCategory;
|
notification.NotificationCategory = notificationCategory;
|
||||||
|
notification.User = user;
|
||||||
|
|
||||||
var notificationTransportService = GetNotificationTransportService(request.IdTransportType);
|
var notificationTransportService = GetNotificationTransportService(request.IdTransportType);
|
||||||
|
|
||||||
await notificationTransportService.SendAsync(notification, cancellationToken);
|
await notificationTransportService.SendAsync(notification, cancellationToken);
|
||||||
|
|
||||||
await notificationRepository.UpdateAsync(notification,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -119,9 +122,6 @@ public class NotificationService
|
|||||||
|
|
||||||
await notificationTransportService.SendRangeAsync(result.Items,
|
await notificationTransportService.SendRangeAsync(result.Items,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
await notificationRepository.UpdateRangeAsync(result.Items,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private INotificationTransportService GetNotificationTransportService(int idTransportType)
|
private INotificationTransportService GetNotificationTransportService(int idTransportType)
|
||||||
|
8385
AsbCloudDb/Migrations/20230725082154_Add_Registration_Date_Notification.Designer.cs
generated
Normal file
8385
AsbCloudDb/Migrations/20230725082154_Add_Registration_Date_Notification.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Registration_Date_Notification : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "registration_date",
|
||||||
|
table: "t_notification",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||||
|
comment: "Дата регистрации уведомления");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "registration_date",
|
||||||
|
table: "t_notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1194,6 +1194,11 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("read_date")
|
.HasColumnName("read_date")
|
||||||
.HasComment("Дата прочтения уведомления");
|
.HasComment("Дата прочтения уведомления");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RegistrationDate")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("registration_date")
|
||||||
|
.HasComment("Дата регистрации уведомления");
|
||||||
|
|
||||||
b.Property<DateTime?>("SentDate")
|
b.Property<DateTime?>("SentDate")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("sent_date")
|
.HasColumnName("sent_date")
|
||||||
|
@ -24,6 +24,9 @@ public class Notification : IId
|
|||||||
[Column("message"), Comment("Сообщение уведомления")]
|
[Column("message"), Comment("Сообщение уведомления")]
|
||||||
public string Message { get; set; } = null!;
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("registration_date"), Comment("Дата регистрации уведомления")]
|
||||||
|
public DateTime RegistrationDate { get; set; }
|
||||||
|
|
||||||
[Column("sent_date"), Comment("Дата отправки уведомления")]
|
[Column("sent_date"), Comment("Дата отправки уведомления")]
|
||||||
public DateTime? SentDate { get; set; }
|
public DateTime? SentDate { get; set; }
|
||||||
|
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Data.SAUB;
|
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
@ -20,6 +16,7 @@ public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, N
|
|||||||
{
|
{
|
||||||
private static IQueryable<Notification> MakeQueryNotification(DbSet<Notification> dbSet)
|
private static IQueryable<Notification> MakeQueryNotification(DbSet<Notification> dbSet)
|
||||||
=> dbSet.Include(n => n.NotificationCategory)
|
=> dbSet.Include(n => n.NotificationCategory)
|
||||||
|
.Include(n => n.User)
|
||||||
.AsNoTracking();
|
.AsNoTracking();
|
||||||
|
|
||||||
public NotificationRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
public NotificationRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
||||||
@ -27,31 +24,6 @@ public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, N
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (!notifications.Any())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
var ids = notifications.Select(d => d.Id).ToArray();
|
|
||||||
|
|
||||||
var existingEntities = await dbSet
|
|
||||||
.Where(d => ids.Contains(d.Id))
|
|
||||||
.AsNoTracking()
|
|
||||||
.Select(d => d.Id)
|
|
||||||
.ToArrayAsync(cancellationToken);
|
|
||||||
|
|
||||||
if (ids.Length > existingEntities.Length)
|
|
||||||
return ICrudRepository<SetpointsRequestDto>.ErrorIdNotFound;
|
|
||||||
|
|
||||||
var entities = notifications.Select(Convert);
|
|
||||||
|
|
||||||
dbContext.Notifications.UpdateRange(entities);
|
|
||||||
|
|
||||||
var result = await dbContext.SaveChangesAsync(cancellationToken);
|
|
||||||
DropCache();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
|
public async Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
|
||||||
NotificationRequest request,
|
NotificationRequest request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
|
@ -387,7 +387,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
await notificationService.NotifyAsync(new NotifyRequest
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
{
|
{
|
||||||
IdUser = user.Id,
|
IdUser = user.Id,
|
||||||
UserEmail = user.Email,
|
|
||||||
IdNotificationCategory = idNotificationCategory,
|
IdNotificationCategory = idNotificationCategory,
|
||||||
Title = subject,
|
Title = subject,
|
||||||
Message = body,
|
Message = body,
|
||||||
@ -410,7 +409,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
await notificationService.NotifyAsync(new NotifyRequest
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
{
|
{
|
||||||
IdUser = user.Id,
|
IdUser = user.Id,
|
||||||
UserEmail = user.Email,
|
|
||||||
IdNotificationCategory = idNotificationCategory,
|
IdNotificationCategory = idNotificationCategory,
|
||||||
Title = subject,
|
Title = subject,
|
||||||
Message = body,
|
Message = body,
|
||||||
@ -436,7 +434,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
await notificationService.NotifyAsync(new NotifyRequest
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
{
|
{
|
||||||
IdUser = user.Id,
|
IdUser = user.Id,
|
||||||
UserEmail = user.Email,
|
|
||||||
IdNotificationCategory = idNotificationCategory,
|
IdNotificationCategory = idNotificationCategory,
|
||||||
Title = subject,
|
Title = subject,
|
||||||
Message = body,
|
Message = body,
|
||||||
@ -458,7 +455,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
await notificationService.NotifyAsync(new NotifyRequest
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
{
|
{
|
||||||
IdUser = user.Id,
|
IdUser = user.Id,
|
||||||
UserEmail = user.Email,
|
|
||||||
IdNotificationCategory = idNotificationCategory,
|
IdNotificationCategory = idNotificationCategory,
|
||||||
Title = subject,
|
Title = subject,
|
||||||
Message = body,
|
Message = body,
|
||||||
|
@ -7,9 +7,11 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Email
|
namespace AsbCloudInfrastructure.Services.Email
|
||||||
{
|
{
|
||||||
@ -48,16 +50,11 @@ namespace AsbCloudInfrastructure.Services.Email
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(notification.UserEmail))
|
var workId = MakeWorkId(notification.User.Email, notification.Title, notification.Message);
|
||||||
{
|
|
||||||
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(new []{ notification.UserEmail }, notification.Title, notification.Message);
|
var workAction = MakeEmailSendWorkAction(notification);
|
||||||
|
|
||||||
var work = new WorkBase(workId, workAction);
|
var work = new WorkBase(workId, workAction);
|
||||||
backgroundWorker.Push(work);
|
backgroundWorker.Push(work);
|
||||||
}
|
}
|
||||||
@ -74,24 +71,18 @@ namespace AsbCloudInfrastructure.Services.Email
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(IEnumerable<string> addresses, string subject, string htmlBody)
|
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(NotificationDto notification)
|
||||||
{
|
{
|
||||||
var mailAddresses = new List<MailAddress>();
|
if(!MailAddress.TryCreate(notification.User.Email, out var mailAddress))
|
||||||
foreach (var address in addresses)
|
Trace.TraceWarning($"Mail {notification.User.Email} is not correct.");
|
||||||
{
|
|
||||||
if (MailAddress.TryCreate(address, out MailAddress? mailAddress))
|
|
||||||
mailAddresses.Add(mailAddress);
|
|
||||||
else
|
|
||||||
Trace.TraceWarning($"Mail {address} is not correct.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mailAddresses.Any())
|
if (mailAddress is null)
|
||||||
throw new ArgumentException($"No valid email found. List:[{string.Join(',', addresses)}]", nameof(addresses));
|
throw new ArgumentInvalidException($"Mail {notification.User.Email} is not null.", nameof(notification.User.Email));
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(subject))
|
if (string.IsNullOrWhiteSpace(notification.Title))
|
||||||
throw new ArgumentInvalidException($"{nameof(subject)} should be set", nameof(subject));
|
throw new ArgumentInvalidException($"{nameof(notification.Title)} should be set", nameof(notification.Title));
|
||||||
|
|
||||||
var workAction = async (string id, IServiceProvider serviceProvider, CancellationToken token) =>
|
return async (_, serviceProvider, token) =>
|
||||||
{
|
{
|
||||||
var from = new MailAddress(sender);
|
var from = new MailAddress(sender);
|
||||||
var message = new MailMessage
|
var message = new MailMessage
|
||||||
@ -99,12 +90,10 @@ namespace AsbCloudInfrastructure.Services.Email
|
|||||||
From = from
|
From = from
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var mailAddress in mailAddresses)
|
message.To.Add(mailAddress.Address);
|
||||||
message.To.Add(mailAddress);
|
|
||||||
|
|
||||||
message.BodyEncoding = System.Text.Encoding.UTF8;
|
message.BodyEncoding = System.Text.Encoding.UTF8;
|
||||||
message.Body = htmlBody;
|
message.Body = notification.Message;
|
||||||
message.Subject = subject;
|
message.Subject = notification.Title;
|
||||||
message.IsBodyHtml = true;
|
message.IsBodyHtml = true;
|
||||||
|
|
||||||
using var client = new SmtpClient(smtpServer);
|
using var client = new SmtpClient(smtpServer);
|
||||||
@ -113,28 +102,23 @@ namespace AsbCloudInfrastructure.Services.Email
|
|||||||
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
||||||
|
|
||||||
await client.SendMailAsync(message, token);
|
await client.SendMailAsync(message, token);
|
||||||
Trace.TraceInformation($"Send email to {string.Join(',', addresses)} subj:{subject} html body count {htmlBody.Length}");
|
|
||||||
|
notification.SentDate = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var notificationRepository = serviceProvider.GetService<INotificationRepository>();
|
||||||
|
|
||||||
|
await notificationRepository!.UpdateAsync(notification, token);
|
||||||
|
|
||||||
|
Trace.TraceInformation($"Send email to {notification.User.Email} subj:{notification.Title} html body count {notification.Message.Length}");
|
||||||
};
|
};
|
||||||
return workAction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string MakeWorkId(IEnumerable<string> addresses, string subject, string content)
|
private static string MakeWorkId(string address, string subject, string content)
|
||||||
{
|
{
|
||||||
var hash = GetHashCode(addresses);
|
var hash = address.GetHashCode();
|
||||||
hash ^= subject.GetHashCode();
|
hash ^= subject.GetHashCode();
|
||||||
hash ^= content.GetHashCode();
|
hash ^= content.GetHashCode();
|
||||||
return hash.ToString("x");
|
return hash.ToString("x");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetHashCode(IEnumerable<string> strings)
|
|
||||||
{
|
|
||||||
int hash = -1397075115;
|
|
||||||
var enumerator = strings.GetEnumerator();
|
|
||||||
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
hash ^= enumerator.Current.GetHashCode();
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,6 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
await notificationService.NotifyAsync(new NotifyRequest
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
{
|
{
|
||||||
IdUser = user.Id,
|
IdUser = user.Id,
|
||||||
UserEmail = user.Email,
|
|
||||||
IdNotificationCategory = idNotificationCategory,
|
IdNotificationCategory = idNotificationCategory,
|
||||||
Title = subject,
|
Title = subject,
|
||||||
Message = body,
|
Message = body,
|
||||||
|
@ -145,6 +145,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
.Returns(1);
|
.Returns(1);
|
||||||
|
|
||||||
notificationService = new NotificationService(notificationCategoryRepositoryMock.Object,
|
notificationService = new NotificationService(notificationCategoryRepositoryMock.Object,
|
||||||
|
userRepositoryMock.Object,
|
||||||
new Mock<INotificationRepository>().Object,
|
new Mock<INotificationRepository>().Object,
|
||||||
new [] { notificationTransportServiceMock.Object });
|
new [] { notificationTransportServiceMock.Object });
|
||||||
|
|
||||||
|
@ -19,15 +19,12 @@ 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(IUserRepository userRepository,
|
public NotificationController(NotificationService notificationService,
|
||||||
NotificationService notificationService,
|
|
||||||
INotificationRepository notificationRepository)
|
INotificationRepository notificationRepository)
|
||||||
{
|
{
|
||||||
this.userRepository = userRepository;
|
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
this.notificationRepository = notificationRepository;
|
this.notificationRepository = notificationRepository;
|
||||||
}
|
}
|
||||||
@ -35,37 +32,14 @@ public class NotificationController : ControllerBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Отправка уведомления
|
/// Отправка уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idUser">Id пользователя</param>
|
/// <param name="request">Параметры запроса</param>
|
||||||
/// <param name="idNotificationCategory">Id категории уведомления. Допустимые: 1</param>
|
|
||||||
/// <param name="title">Заголовок уведомления</param>
|
|
||||||
/// <param name="message">Сообщение уведомления</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(NotifyRequest request, CancellationToken cancellationToken)
|
||||||
[Required] [Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
|
|
||||||
int idNotificationCategory,
|
|
||||||
[Required] string title,
|
|
||||||
[Required] string message,
|
|
||||||
[Required]
|
|
||||||
[Range(minimum: 0, maximum: 1, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0, 1")]
|
|
||||||
int idTransportType,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
var user = await userRepository.GetOrDefaultAsync(idUser, cancellationToken)
|
await notificationService.NotifyAsync(request, 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();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
@ -13,12 +14,16 @@ public class SignalRNotificationTransportService : INotificationTransportService
|
|||||||
{
|
{
|
||||||
private readonly ConnectionManagerService connectionManagerService;
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
private readonly IHubContext<NotificationHub> notificationHubContext;
|
private readonly IHubContext<NotificationHub> notificationHubContext;
|
||||||
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
private readonly SemaphoreSlim semaphoreSlim = new (1, 1);
|
||||||
|
|
||||||
public SignalRNotificationTransportService(ConnectionManagerService connectionManagerService,
|
public SignalRNotificationTransportService(ConnectionManagerService connectionManagerService,
|
||||||
IHubContext<NotificationHub> notificationHubContext)
|
IHubContext<NotificationHub> notificationHubContext,
|
||||||
|
INotificationRepository notificationRepository)
|
||||||
{
|
{
|
||||||
this.connectionManagerService = connectionManagerService;
|
this.connectionManagerService = connectionManagerService;
|
||||||
this.notificationHubContext = notificationHubContext;
|
this.notificationHubContext = notificationHubContext;
|
||||||
|
this.notificationRepository = notificationRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IdTransportType => 0;
|
public int IdTransportType => 0;
|
||||||
@ -38,6 +43,12 @@ public class SignalRNotificationTransportService : INotificationTransportService
|
|||||||
.SendAsync(method,
|
.SendAsync(method,
|
||||||
notification,
|
notification,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
|
await semaphoreSlim.WaitAsync(cancellationToken);
|
||||||
|
|
||||||
|
await notificationRepository.UpdateAsync(notification, cancellationToken);
|
||||||
|
|
||||||
|
semaphoreSlim.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user