diff --git a/AsbCloudApp/Requests/NotificationRequest.cs b/AsbCloudApp/Requests/NotificationRequest.cs index 955a6b8b..197b142a 100644 --- a/AsbCloudApp/Requests/NotificationRequest.cs +++ b/AsbCloudApp/Requests/NotificationRequest.cs @@ -8,7 +8,7 @@ public class NotificationRequest : RequestBase /// /// Получение отправленных/не отправленных уведомлений /// - public bool IsSent { get; set; } = false; + public bool? IsSent { get; set; } = false; /// /// Id типа доставки уведомления diff --git a/AsbCloudApp/Services/Notifications/INotificationService.cs b/AsbCloudApp/Services/Notifications/INotificationService.cs deleted file mode 100644 index 30498230..00000000 --- a/AsbCloudApp/Services/Notifications/INotificationService.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Requests; - -namespace AsbCloudApp.Services.Notifications; - -/// -/// Интерфейс для работы с уведомлениями -/// -public interface INotificationService -{ - /// - /// Отправка нового уведомления - /// - /// - /// - /// - /// - /// - /// - /// - Task NotifyAsync(int idUser, - int idNotificationCategory, - string title, - string message, - int idTransportType, - CancellationToken cancellationToken); - - /// - /// Обновление уведомления - /// - /// - /// - /// - /// - Task UpdateNotificationAsync(int idNotification, - bool isRead, - CancellationToken cancellationToken); - - /// - /// Отправка уведомлений, которые не были отправлены - /// - /// - /// - /// - /// - Task ResendNotificationAsync(int idUser, - NotificationRequest request, - CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/AsbCloudApp/Services/Notifications/NotificationService.cs b/AsbCloudApp/Services/Notifications/NotificationService.cs new file mode 100644 index 00000000..849a2833 --- /dev/null +++ b/AsbCloudApp/Services/Notifications/NotificationService.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; + +namespace AsbCloudApp.Services.Notifications; + +/// +/// Сервис для работы с уведомлениями +/// +public class NotificationService +{ + private readonly ICrudRepository notificationCategoryRepository; + private readonly INotificationRepository notificationRepository; + private readonly IEnumerable notificationTransportServices; + + /// + /// Сервис для работы с уведомлениями + /// + /// + /// + /// + public NotificationService(ICrudRepository notificationCategoryRepository, + INotificationRepository notificationRepository, + IEnumerable notificationTransportServices) + { + this.notificationCategoryRepository = notificationCategoryRepository; + this.notificationRepository = notificationRepository; + this.notificationTransportServices = notificationTransportServices; + } + + /// + /// Отправка нового уведомления + /// + /// + /// + /// + /// + /// + /// + /// + public async Task NotifyAsync(int idUser, + int idNotificationCategory, + string title, + string message, + int idTransportType, + CancellationToken cancellationToken) + { + var notificationCategory = await notificationCategoryRepository + .GetOrDefaultAsync(idNotificationCategory, cancellationToken) + ?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(idNotificationCategory)); + + var notification = new NotificationDto() + { + IdUser = idUser, + IdNotificationCategory = idNotificationCategory, + Title = title, + Message = message, + IdTransportType = idTransportType + }; + + notification.Id = await notificationRepository.InsertAsync(notification, + cancellationToken); + + notification.NotificationCategory = notificationCategory; + + var notificationTransportService = GetNotificationTransportService(idTransportType); + + await notificationTransportService.SendAsync(notification, cancellationToken); + + await notificationRepository.UpdateAsync(notification, + cancellationToken); + } + + /// + /// Обновление уведомления + /// + /// + /// + /// + /// + public async Task UpdateNotificationAsync(int idNotification, + bool isRead, + CancellationToken cancellationToken) + { + var notification = await notificationRepository.GetOrDefaultAsync(idNotification, + cancellationToken) + ?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification)); + + if (isRead) + { + if (notification.SentDate == null) + throw new ArgumentInvalidException("Уведомление не может быть прочитано", nameof(isRead)); + + notification.SentDate = DateTime.UtcNow; + } + + await notificationRepository.UpdateAsync(notification, + cancellationToken); + } + + /// + /// Отправка уведомлений, которые не были отправлены + /// + /// + /// + /// + /// + public async Task ResendNotificationAsync(int idUser, + NotificationRequest request, + CancellationToken cancellationToken) + { + if (!request.IdTransportType.HasValue) + throw new ArgumentInvalidException("Id типа доставки уведомления должен иметь значение", + nameof(request.IdTransportType)); + + var result = await notificationRepository.GetNotificationsAsync(idUser, + request, + cancellationToken); + + var notificationTransportService = GetNotificationTransportService(request.IdTransportType.Value); + + await notificationTransportService.SendRangeAsync(result.Items, + cancellationToken); + + await notificationRepository.UpdateRangeAsync(result.Items, + cancellationToken); + } + + private INotificationTransportService GetNotificationTransportService(int idTransportType) + { + var notificationTransportService = notificationTransportServices + .FirstOrDefault(s => s.IdTransportType == idTransportType) + ?? throw new ArgumentInvalidException("Доставщик уведомлений не найден", nameof(idTransportType)); + + return notificationTransportService; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 696a0439..6ddc0248 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -24,7 +24,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using AsbCloudApp.Services.Notifications; -using AsbCloudInfrastructure.Services.Notifications; namespace AsbCloudInfrastructure { @@ -150,7 +149,7 @@ namespace AsbCloudInfrastructure services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient, CrudCacheRepositoryBase>(); diff --git a/AsbCloudInfrastructure/Repository/NotificationRepository.cs b/AsbCloudInfrastructure/Repository/NotificationRepository.cs index cfc99cb9..90799208 100644 --- a/AsbCloudInfrastructure/Repository/NotificationRepository.cs +++ b/AsbCloudInfrastructure/Repository/NotificationRepository.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -46,7 +47,9 @@ public class NotificationRepository : CrudCacheRepositoryBase> GetNotificationsAsync(int idUser, @@ -65,7 +68,7 @@ public class NotificationRepository : CrudCacheRepositoryBase x.NotificationCategory) - .Where(n => n.IdUser == idUser) - .AsQueryable(); + .Where(n => n.IdUser == idUser); - if (!request.IsSent) - query = query.Where(n => n.SentDate == null); + if (request.IsSent.HasValue) + { + if(request.IsSent.Value) + query = query.Where(n => n.SentDate != null); + else + query = query.Where(n => n.SentDate == null); + } if (request.IdTransportType.HasValue) query = query.Where(n => n.IdTransportType == request.IdTransportType); diff --git a/AsbCloudInfrastructure/Services/Notifications/NotificationService.cs b/AsbCloudInfrastructure/Services/Notifications/NotificationService.cs deleted file mode 100644 index 0406a3d4..00000000 --- a/AsbCloudInfrastructure/Services/Notifications/NotificationService.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Repositories; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudApp.Services.Notifications; - -namespace AsbCloudInfrastructure.Services.Notifications; - -public class NotificationService : INotificationService -{ - private readonly ICrudRepository notificationCategoryRepository; - private readonly INotificationRepository notificationRepository; - private readonly IEnumerable notificationTransportServices; - - public NotificationService(ICrudRepository notificationCategoryRepository, - INotificationRepository notificationRepository, - IEnumerable notificationTransportServices) - { - this.notificationCategoryRepository = notificationCategoryRepository; - this.notificationRepository = notificationRepository; - this.notificationTransportServices = notificationTransportServices; - } - - public async Task NotifyAsync(int idUser, - int idNotificationCategory, - string title, - string message, - int idTransportType, - CancellationToken cancellationToken) - { - var notificationCategory = await notificationCategoryRepository - .GetOrDefaultAsync(idNotificationCategory, cancellationToken); - - if(notificationCategory is null) - throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(idNotificationCategory)); - - var notification = new NotificationDto() - { - IdUser = idUser, - IdNotificationCategory = idNotificationCategory, - Title = title, - Message = message, - IdTransportType = idTransportType - }; - - notification.Id = await notificationRepository.InsertAsync(notification, - cancellationToken); - - notification.NotificationCategory = notificationCategory; - - var notificationTransportService = GetNotificationTransportService(idTransportType); - - await notificationTransportService.SendAsync(notification, cancellationToken); - - await notificationRepository.UpdateAsync(notification, - cancellationToken); - } - - public async Task UpdateNotificationAsync(int idNotification, - bool isRead, - CancellationToken cancellationToken) - { - var notification = await notificationRepository.GetOrDefaultAsync(idNotification, - cancellationToken) - ?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification)); - - if (isRead) - { - if (notification.SentDate == null) - throw new ArgumentInvalidException("Уведомление не может быть прочитано", nameof(isRead)); - - notification.SentDate = DateTime.UtcNow; - } - - await notificationRepository.UpdateAsync(notification, - cancellationToken); - } - - public async Task ResendNotificationAsync(int idUser, - NotificationRequest request, - CancellationToken cancellationToken) - { - if (!request.IdTransportType.HasValue) - throw new ArgumentInvalidException("Id типа доставки уведомления должен иметь значение", - nameof(request.IdTransportType)); - - var result = await notificationRepository.GetNotificationsAsync(idUser, - request, - cancellationToken); - - var notificationTransportService = GetNotificationTransportService(request.IdTransportType.Value); - - await notificationTransportService.SendRangeAsync(result.Items, - cancellationToken); - - await notificationRepository.UpdateRangeAsync(result.Items, - cancellationToken); - } - - private INotificationTransportService GetNotificationTransportService(int idTransportType) - { - var notificationTransportService = notificationTransportServices - .FirstOrDefault(s => s.IdTransportType == idTransportType) - ?? throw new ArgumentInvalidException("Доставщик уведомлений не найден", nameof(idTransportType)); - - return notificationTransportService; - } -} \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/NotificationController.cs b/AsbCloudWebApi/Controllers/NotificationController.cs index 8f0f8975..2e1bb976 100644 --- a/AsbCloudWebApi/Controllers/NotificationController.cs +++ b/AsbCloudWebApi/Controllers/NotificationController.cs @@ -19,10 +19,10 @@ namespace AsbCloudWebApi.Controllers; [Route("api/notification")] public class NotificationController : ControllerBase { - private readonly INotificationService notificationService; + private readonly NotificationService notificationService; private readonly INotificationRepository notificationRepository; - public NotificationController(INotificationService notificationService, + public NotificationController(NotificationService notificationService, INotificationRepository notificationRepository) { this.notificationService = notificationService; diff --git a/AsbCloudWebApi/DependencyInjection.cs b/AsbCloudWebApi/DependencyInjection.cs index 9f15b707..7477f745 100644 --- a/AsbCloudWebApi/DependencyInjection.cs +++ b/AsbCloudWebApi/DependencyInjection.cs @@ -24,7 +24,7 @@ namespace AsbCloudWebApi { services.AddSwaggerGen(c => { - c.MapType(() => new OpenApiSchema { Type = "string", Example = new OpenApiString("1.00:00:00") }); + c.MapType(() => new OpenApiSchema { Type = "string", Example = new OpenApiString("0.00:00:00") }); c.MapType(() => new OpenApiSchema { Type = "string", Format = "date" }); c.MapType(() => new OpenApiSchema { diff --git a/AsbCloudWebApi/SignalR/NotificationHub.cs b/AsbCloudWebApi/SignalR/NotificationHub.cs index ea1f6885..5422e30e 100644 --- a/AsbCloudWebApi/SignalR/NotificationHub.cs +++ b/AsbCloudWebApi/SignalR/NotificationHub.cs @@ -13,49 +13,41 @@ namespace AsbCloudWebApi.SignalR; public class NotificationHub : BaseHub { private readonly ConnectionManagerService connectionManagerService; - private readonly INotificationService notificationService; + private readonly NotificationService notificationService; public NotificationHub(ConnectionManagerService connectionManagerService, - INotificationService notificationService) + NotificationService notificationService) { this.connectionManagerService = connectionManagerService; this.notificationService = notificationService; } - public async Task OnConnected(NotificationRequest request) + public override async Task OnConnectedAsync() { - try - { - await base.OnConnectedAsync(); - - var idUser = Context.User?.GetUserId(); + var idUser = Context.User?.GetUserId(); - if (!idUser.HasValue) - return; + if (!idUser.HasValue) + return; - string connectionId = Context.ConnectionId; + string connectionId = Context.ConnectionId; - connectionManagerService.AddOrUpdateConnection(idUser.Value, connectionId); + connectionManagerService.AddOrUpdateConnection(idUser.Value, connectionId); - await notificationService.ResendNotificationAsync(idUser.Value, - request, - CancellationToken.None); - } - catch (Exception e) - { - Console.WriteLine(e); - } + await base.OnConnectedAsync(); + + await notificationService.ResendNotificationAsync(idUser.Value, + new NotificationRequest { IsSent = false, IdTransportType = 0}, + CancellationToken.None); } - public async Task OnDisconnected() - { - await base.OnDisconnectedAsync(null); - + public override async Task OnDisconnectedAsync(Exception? exception) + { var idUser = Context.User?.GetUserId(); if (!idUser.HasValue) return; connectionManagerService.RemoveConnection(idUser.Value); + await base.OnDisconnectedAsync(exception); } } \ No newline at end of file diff --git a/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs b/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs index d8c10adc..848f2dbd 100644 --- a/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs +++ b/AsbCloudWebApi/SignalR/Services/SignalRNotificationTransportService.cs @@ -26,7 +26,7 @@ public class SignalRNotificationTransportService : INotificationTransportService public async Task SendAsync(NotificationDto notification, CancellationToken cancellationToken) { - const string method = "notifications"; + const string method = "receiveNotifications"; var connectionId = connectionManagerService.GetConnectionIdByUserId(notification.IdUser); @@ -44,8 +44,8 @@ public class SignalRNotificationTransportService : INotificationTransportService public Task SendRangeAsync(IEnumerable notifications, CancellationToken cancellationToken) { - var tasks = Array.ConvertAll(notifications.ToArray(), notification => - SendAsync(notification, cancellationToken)); + var tasks = notifications + .Select(notification => SendAsync(notification, cancellationToken)); return Task.WhenAll(tasks); } diff --git a/SignalRTestClient/Program.cs b/SignalRTestClient/Program.cs index f16872bf..487f1253 100644 --- a/SignalRTestClient/Program.cs +++ b/SignalRTestClient/Program.cs @@ -10,7 +10,7 @@ internal class Program { var connectionBuilder = new HubConnectionBuilder(); var connection = connectionBuilder - .WithUrl("http://test.digitaldrilling.ru/hubs/telemetry", connectionOptions => { + .WithUrl("http://localhost:5000/hubs/notifications", connectionOptions => { connectionOptions.AccessTokenProvider = AccessTokenProvider; }) .WithAutomaticReconnect() @@ -25,9 +25,10 @@ internal class Program Console.WriteLine("connecting"); connection.StartAsync().Wait(); - Console.WriteLine("AddToGroup"); - connection.SendCoreAsync("AddToGroup", new object[] { "well_1" }).Wait(); - var subsction = connection.On("UpdateProcessMap", (str1) => { + //Console.WriteLine("OnConnected"); + //connection.SendCoreAsync("OnConnected", new object[] { }, CancellationToken.None).Wait(); + + var subsction = connection.On("receiveNotifications", (str1) => { Console.WriteLine(str1); } );