forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/APD
This commit is contained in:
commit
007a3f1e95
@ -16,7 +16,7 @@ public class NotificationDto : IId
|
|||||||
/// Id получателя уведомления
|
/// Id получателя уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdUser { get; set; }
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id категории уведомления
|
/// Id категории уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -32,6 +32,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>
|
||||||
@ -41,7 +46,7 @@ public class NotificationDto : IId
|
|||||||
/// Дата прочтения уведомления
|
/// Дата прочтения уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? ReadDate { get; set; }
|
public DateTime? ReadDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Состояние уведомления
|
/// Состояние уведомления
|
||||||
/// 0 - Зарегистрировано,
|
/// 0 - Зарегистрировано,
|
||||||
@ -60,11 +65,30 @@ public class NotificationDto : IId
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
SentDate = null;
|
||||||
|
ReadDate = null;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
SentDate = DateTime.UtcNow;
|
||||||
|
ReadDate = null;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
SentDate = DateTime.UtcNow;
|
||||||
|
ReadDate = DateTime.UtcNow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id типа доставки уведомления
|
/// Id типа доставки уведомления
|
||||||
/// 0 - SignalR
|
/// 0 - SignalR
|
||||||
|
/// 1 - Email
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdTransportType { get; set; }
|
public int IdTransportType { get; set; }
|
||||||
|
|
||||||
|
@ -50,6 +50,11 @@ namespace AsbCloudApp.Data
|
|||||||
/// 2 - завершена
|
/// 2 - завершена
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdState { get; set; }
|
public int IdState { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название текущей секции
|
||||||
|
/// </summary>
|
||||||
|
public string? Section { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Коэф-т использования автоподачи долота (суммарный ротор + слайд)
|
/// Коэф-т использования автоподачи долота (суммарный ротор + слайд)
|
||||||
@ -89,6 +94,31 @@ namespace AsbCloudApp.Data
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public PlanFactDto<double?> ROP { get; set; } = null!;
|
public PlanFactDto<double?> ROP { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Нагрузка на долота, Т
|
||||||
|
/// </summary>
|
||||||
|
public PlanFactDto<double?> AxialLoad { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обороты ротора
|
||||||
|
/// </summary>
|
||||||
|
public PlanFactDto<double?> TopDriveSpeed { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Момент ротора кн/м
|
||||||
|
/// </summary>
|
||||||
|
public PlanFactDto<double?> TopDriveTorque { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Перепад давления
|
||||||
|
/// </summary>
|
||||||
|
public PlanFactDto<double?> Pressure { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Действующее задание давления, атм
|
||||||
|
/// </summary>
|
||||||
|
public double? PressureSp { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Плановая и текущая глубина
|
/// Плановая и текущая глубина
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
namespace AsbCloudApp.IntegrationEvents.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс маркер для доменных событий
|
||||||
|
/// </summary>
|
||||||
|
public interface IIntegrationEvent { }
|
@ -0,0 +1,19 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.IntegrationEvents.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обработчик событий
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public interface IIntegrationEventHandler<in T> where T: IIntegrationEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Метод обработки события
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="integrationEvent"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task HandleAsync(T integrationEvent, CancellationToken cancellationToken);
|
||||||
|
}
|
9
AsbCloudApp/IntegrationEvents/UpdateWellInfoEvent.cs
Normal file
9
AsbCloudApp/IntegrationEvents/UpdateWellInfoEvent.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using AsbCloudApp.IntegrationEvents.Interfaces;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.IntegrationEvents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление показателей бурения
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="IdWell"></param>
|
||||||
|
public record UpdateWellInfoEvent(int IdWell) : IIntegrationEvent;
|
@ -1,9 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AsbCloudApp.Repositories;
|
namespace AsbCloudApp.Repositories;
|
||||||
|
|
||||||
@ -12,15 +12,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>
|
||||||
@ -31,4 +22,41 @@ public interface INotificationRepository : ICrudRepository<NotificationDto>
|
|||||||
Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
|
Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
|
||||||
NotificationRequest request,
|
NotificationRequest request,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение всех уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="isSent"></param>
|
||||||
|
/// <param name="idTransportType"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<NotificationDto>> GetAllAsync(int? idUser, bool? isSent, int? idTransportType,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notifications"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление уведомлений по параметрам
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> DeleteAsync(NotificationDeleteRequest request,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение количества непрочтенных уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="idTransportType"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> GetUnreadCountAsync(int idUser, int idTransportType, CancellationToken cancellationToken);
|
||||||
}
|
}
|
24
AsbCloudApp/Requests/NotificationDeleteRequest.cs
Normal file
24
AsbCloudApp/Requests/NotificationDeleteRequest.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Запрос для удаления уведомлений
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationDeleteRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор категории
|
||||||
|
/// </summary>
|
||||||
|
public int? IdCategory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Меньше или равно дате отправки
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? LtSentDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Меньше или равно дате прочтения
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? LtReadDate { get; set; }
|
||||||
|
}
|
40
AsbCloudApp/Requests/NotifyRequest.cs
Normal file
40
AsbCloudApp/Requests/NotifyRequest.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры запроса для отправки уведомления
|
||||||
|
/// </summary>
|
||||||
|
public class NotifyRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id получателя уведомления
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id категории уведомления. Допустимое значение параметра: 1
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
[Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
|
||||||
|
public int IdNotificationCategory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заголовок уведомления
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сообщение уведомления
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id типа доставки уведомления. Допустимое значение: 0, 1
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,7 @@ public interface INotificationTransportService
|
|||||||
int IdTransportType { get; }
|
int IdTransportType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Отправка одного уведомлений
|
/// Отправка одного уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="notification"></param>
|
/// <param name="notification"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
|
@ -33,48 +33,34 @@ public class NotificationService
|
|||||||
this.notificationRepository = notificationRepository;
|
this.notificationRepository = notificationRepository;
|
||||||
this.notificationTransportServices = notificationTransportServices;
|
this.notificationTransportServices = notificationTransportServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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(request.IdNotificationCategory, cancellationToken)
|
||||||
.GetOrDefaultAsync(idNotificationCategory, cancellationToken)
|
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
||||||
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(idNotificationCategory));
|
|
||||||
|
|
||||||
var notification = new NotificationDto()
|
var notification = new NotificationDto
|
||||||
{
|
{
|
||||||
IdUser = idUser,
|
IdUser = request.IdUser,
|
||||||
IdNotificationCategory = idNotificationCategory,
|
RegistrationDate = DateTime.UtcNow,
|
||||||
Title = title,
|
IdNotificationCategory = notificationCategory.Id,
|
||||||
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, cancellationToken);
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
notification.NotificationCategory = notificationCategory;
|
notification.NotificationCategory = notificationCategory;
|
||||||
|
|
||||||
var notificationTransportService = GetNotificationTransportService(idTransportType);
|
var notificationTransportService = GetTransportService(request.IdTransportType);
|
||||||
|
|
||||||
await notificationTransportService.SendAsync(notification, cancellationToken);
|
await notificationTransportService.SendAsync(notification, cancellationToken);
|
||||||
|
|
||||||
await notificationRepository.UpdateAsync(notification,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -84,21 +70,17 @@ public class NotificationService
|
|||||||
/// <param name="isRead"></param>
|
/// <param name="isRead"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task UpdateNotificationAsync(int idNotification,
|
public async Task UpdateAsync(int idNotification,
|
||||||
bool isRead,
|
bool isRead,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var notification = await notificationRepository.GetOrDefaultAsync(idNotification,
|
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken)
|
||||||
cancellationToken)
|
|
||||||
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
||||||
|
|
||||||
if (isRead)
|
if(isRead && !notification.SentDate.HasValue)
|
||||||
{
|
throw new ArgumentInvalidException("Уведомление не может быть прочитано", nameof(isRead));
|
||||||
if (notification.SentDate == null)
|
|
||||||
throw new ArgumentInvalidException("Уведомление не может быть прочитано", nameof(isRead));
|
notification.ReadDate = isRead ? DateTime.UtcNow : null;
|
||||||
|
|
||||||
notification.SentDate = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
await notificationRepository.UpdateAsync(notification,
|
await notificationRepository.UpdateAsync(notification,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
@ -111,28 +93,21 @@ public class NotificationService
|
|||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task ResendNotificationAsync(int idUser,
|
public async Task RenotifyAsync(int idUser, CancellationToken cancellationToken)
|
||||||
NotificationRequest request,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
if (!request.IdTransportType.HasValue)
|
const int idTransportType = 0;
|
||||||
throw new ArgumentInvalidException("Id типа доставки уведомления должен иметь значение",
|
|
||||||
nameof(request.IdTransportType));
|
var notifications = await notificationRepository.GetAllAsync(idUser, false,
|
||||||
|
idTransportType,
|
||||||
var result = await notificationRepository.GetNotificationsAsync(idUser,
|
|
||||||
request,
|
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
var notificationTransportService = GetNotificationTransportService(request.IdTransportType.Value);
|
var notificationTransportService = GetTransportService(idTransportType);
|
||||||
|
|
||||||
await notificationTransportService.SendRangeAsync(result.Items,
|
await notificationTransportService.SendRangeAsync(notifications,
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
await notificationRepository.UpdateRangeAsync(result.Items,
|
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private INotificationTransportService GetNotificationTransportService(int idTransportType)
|
private INotificationTransportService GetTransportService(int idTransportType)
|
||||||
{
|
{
|
||||||
var notificationTransportService = notificationTransportServices
|
var notificationTransportService = notificationTransportServices
|
||||||
.FirstOrDefault(s => s.IdTransportType == idTransportType)
|
.FirstOrDefault(s => s.IdTransportType == 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1276,6 +1276,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; }
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Background
|
namespace AsbCloudInfrastructure.Background
|
||||||
{
|
{
|
||||||
# nullable enable
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сервис для фонового выполнения работы
|
/// Сервис для фонового выполнения работы
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -94,5 +93,4 @@ namespace AsbCloudInfrastructure.Background
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Background;
|
||||||
|
|
||||||
|
public class NotificationBackgroundWorker : BackgroundWorker
|
||||||
|
{
|
||||||
|
public NotificationBackgroundWorker(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -107,13 +107,13 @@ 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));
|
||||||
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
|
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
|
||||||
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
||||||
services.AddSingleton<BackgroundWorker>();
|
services.AddSingleton<BackgroundWorker>();
|
||||||
|
services.AddSingleton<NotificationBackgroundWorker>();
|
||||||
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
||||||
|
|
||||||
services.AddTransient<IAuthService, AuthService>();
|
services.AddTransient<IAuthService, AuthService>();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
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;
|
||||||
@ -12,45 +11,21 @@ using AsbCloudDb;
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Repository;
|
namespace AsbCloudInfrastructure.Repository;
|
||||||
|
|
||||||
public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, Notification>, INotificationRepository
|
public class NotificationRepository : CrudRepositoryBase<NotificationDto, Notification>, INotificationRepository
|
||||||
{
|
{
|
||||||
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 context)
|
||||||
: base(dbContext, memoryCache, MakeQueryNotification)
|
: base(context, MakeQueryNotification)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@ -61,7 +36,7 @@ public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, N
|
|||||||
|
|
||||||
var query = BuildQuery(idUser, request);
|
var query = BuildQuery(idUser, request);
|
||||||
|
|
||||||
var result = new PaginationContainer<NotificationDto>()
|
var result = new PaginationContainer<NotificationDto>
|
||||||
{
|
{
|
||||||
Skip = skip,
|
Skip = skip,
|
||||||
Take = take,
|
Take = take,
|
||||||
@ -82,20 +57,92 @@ public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, N
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IQueryable<Notification> BuildQuery(int idUser,
|
public async Task<IEnumerable<NotificationDto>> GetAllAsync(int? idUser, bool? isSent, int? idTransportType,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var query = dbContext.Notifications.AsQueryable();
|
||||||
|
|
||||||
|
if (idUser.HasValue)
|
||||||
|
query = query.Where(n => n.IdUser == idUser);
|
||||||
|
|
||||||
|
if(isSent.HasValue)
|
||||||
|
query = isSent.Value ?
|
||||||
|
query.Where(n => n.SentDate != null)
|
||||||
|
: query.Where(n => n.SentDate == null);
|
||||||
|
|
||||||
|
if (idTransportType.HasValue)
|
||||||
|
query = query.Where(n => n.IdTransportType == idTransportType);
|
||||||
|
|
||||||
|
return await query.AsNoTracking().Select(n => n.Adapt<NotificationDto>())
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!notifications.Any())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var ids = notifications.Select(d => d.Id);
|
||||||
|
|
||||||
|
var existingEntities = await dbSet
|
||||||
|
.Where(d => ids.Contains(d.Id))
|
||||||
|
.AsNoTracking()
|
||||||
|
.Select(d => d.Id)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (ids.Count() > existingEntities.Length)
|
||||||
|
return ICrudRepository<SetpointsRequestDto>.ErrorIdNotFound;
|
||||||
|
|
||||||
|
var entities = notifications.Select(Convert);
|
||||||
|
|
||||||
|
dbContext.Notifications.UpdateRange(entities);
|
||||||
|
|
||||||
|
return await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> DeleteAsync(NotificationDeleteRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var query = dbContext.Notifications
|
||||||
|
.Include(n => n.NotificationCategory)
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
|
if (request.IdCategory.HasValue)
|
||||||
|
query = query.Where(n => n.IdNotificationCategory == request.IdCategory.Value);
|
||||||
|
|
||||||
|
if (request.LtSentDate.HasValue)
|
||||||
|
query = query.Where(n => n.SentDate <= request.LtSentDate.Value);
|
||||||
|
|
||||||
|
if (request.LtReadDate.HasValue)
|
||||||
|
query = query.Where(n => n.ReadDate <= request.LtReadDate.Value);
|
||||||
|
|
||||||
|
dbContext.Notifications.RemoveRange(query);
|
||||||
|
|
||||||
|
return dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> GetUnreadCountAsync(int idUser, int idTransportType, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return dbContext.Notifications
|
||||||
|
.Where(n => !n.ReadDate.HasValue &&
|
||||||
|
n.SentDate.HasValue &&
|
||||||
|
n.IdUser == idUser &&
|
||||||
|
n.IdTransportType == idTransportType)
|
||||||
|
.CountAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQueryable<Notification> BuildQuery(int idUser,
|
||||||
NotificationRequest request)
|
NotificationRequest request)
|
||||||
{
|
{
|
||||||
var query = dbContext.Notifications
|
var query = dbContext.Notifications
|
||||||
.Include(x => x.NotificationCategory)
|
.Include(x => x.NotificationCategory)
|
||||||
.Where(n => n.IdUser == idUser);
|
.Where(n => n.IdUser == idUser);
|
||||||
|
|
||||||
if (request.IsSent.HasValue)
|
if (request.IsSent.HasValue)
|
||||||
{
|
{
|
||||||
if(request.IsSent.Value)
|
query = request.IsSent.Value ?
|
||||||
query = query.Where(n => n.SentDate != null);
|
query.Where(n => n.SentDate != null)
|
||||||
else
|
: query.Where(n => n.SentDate == null);
|
||||||
query = query.Where(n => n.SentDate == null);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (request.IdTransportType.HasValue)
|
if (request.IdTransportType.HasValue)
|
||||||
query = query.Where(n => n.IdTransportType == request.IdTransportType);
|
query = query.Where(n => n.IdTransportType == request.IdTransportType);
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
@ -23,15 +26,18 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
public class DrillingProgramService : IDrillingProgramService
|
public class DrillingProgramService : IDrillingProgramService
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, DrillingProgramCreateError> drillingProgramCreateErrors = new Dictionary<string, DrillingProgramCreateError>();
|
private static readonly Dictionary<string, DrillingProgramCreateError> drillingProgramCreateErrors = new Dictionary<string, DrillingProgramCreateError>();
|
||||||
|
|
||||||
private readonly IAsbCloudDbContext context;
|
private readonly IAsbCloudDbContext context;
|
||||||
private readonly FileService fileService;
|
private readonly FileService fileService;
|
||||||
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 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;
|
||||||
private const int idFileCategoryDrillingProgramPartsEnd = 1100;
|
private const int idFileCategoryDrillingProgramPartsEnd = 1100;
|
||||||
@ -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,14 @@ 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,
|
||||||
|
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 +406,14 @@ 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,
|
||||||
|
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 +431,14 @@ 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,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,7 +451,15 @@ 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,
|
||||||
|
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
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.Email
|
||||||
|
{
|
||||||
|
|
||||||
|
public class EmailNotificationTransportService : INotificationTransportService
|
||||||
|
{
|
||||||
|
private readonly BackgroundWorker backgroundWorker;
|
||||||
|
private readonly bool IsConfigured;
|
||||||
|
private readonly string sender;
|
||||||
|
private readonly string smtpServer;
|
||||||
|
private readonly string smtpPassword;
|
||||||
|
|
||||||
|
public EmailNotificationTransportService(BackgroundWorker backgroundWorker,
|
||||||
|
IConfiguration configuration)
|
||||||
|
{
|
||||||
|
sender = configuration.GetValue("email:sender", string.Empty);
|
||||||
|
smtpPassword = configuration.GetValue("email:password", string.Empty);
|
||||||
|
smtpServer = configuration.GetValue("email:smtpServer", string.Empty);
|
||||||
|
|
||||||
|
var configError = string.IsNullOrEmpty(sender) ||
|
||||||
|
string.IsNullOrEmpty(smtpPassword) ||
|
||||||
|
string.IsNullOrEmpty(smtpServer);
|
||||||
|
|
||||||
|
IsConfigured = !configError;
|
||||||
|
|
||||||
|
this.backgroundWorker = backgroundWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IdTransportType => 1;
|
||||||
|
|
||||||
|
public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!IsConfigured)
|
||||||
|
{
|
||||||
|
Trace.TraceWarning("smtp is not configured");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var workId = MakeWorkId(notification.IdUser, notification.Title, notification.Message);
|
||||||
|
if (!backgroundWorker.Contains(workId))
|
||||||
|
{
|
||||||
|
var workAction = MakeEmailSendWorkAction(notification);
|
||||||
|
|
||||||
|
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(NotificationDto notification)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Title))
|
||||||
|
throw new ArgumentInvalidException($"{nameof(notification.Title)} should be set", nameof(notification.Title));
|
||||||
|
|
||||||
|
return async (_, serviceProvider, token) =>
|
||||||
|
{
|
||||||
|
var notificationRepository = serviceProvider.GetRequiredService<INotificationRepository>();
|
||||||
|
var userRepository = serviceProvider.GetRequiredService<IUserRepository>();
|
||||||
|
|
||||||
|
var user = await userRepository.GetOrDefaultAsync(notification.IdUser, token)
|
||||||
|
?? throw new ArgumentInvalidException("Пользователь не найден" , nameof(notification.IdUser));
|
||||||
|
|
||||||
|
if(!MailAddress.TryCreate(user.Email, out var mailAddress))
|
||||||
|
Trace.TraceWarning($"Mail {user.Email} is not correct.");
|
||||||
|
|
||||||
|
if (mailAddress is null)
|
||||||
|
throw new ArgumentInvalidException($"Mail {user.Email} is not null.", nameof(user.Email));
|
||||||
|
|
||||||
|
var from = new MailAddress(sender);
|
||||||
|
var message = new MailMessage
|
||||||
|
{
|
||||||
|
From = from
|
||||||
|
};
|
||||||
|
|
||||||
|
message.To.Add(mailAddress.Address);
|
||||||
|
message.BodyEncoding = System.Text.Encoding.UTF8;
|
||||||
|
message.Body = notification.Message;
|
||||||
|
message.Subject = notification.Title;
|
||||||
|
message.IsBodyHtml = true;
|
||||||
|
|
||||||
|
using var client = new SmtpClient(smtpServer);
|
||||||
|
client.EnableSsl = true;
|
||||||
|
client.UseDefaultCredentials = false;
|
||||||
|
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
||||||
|
|
||||||
|
await client.SendMailAsync(message, token);
|
||||||
|
|
||||||
|
notification.SentDate = DateTime.UtcNow;
|
||||||
|
|
||||||
|
await notificationRepository.UpdateAsync(notification, token);
|
||||||
|
|
||||||
|
Trace.TraceInformation($"Send email to {user.Email} subj:{notification.Title} html body count {notification.Message.Length}");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string MakeWorkId(int idUser, string subject, string content)
|
||||||
|
{
|
||||||
|
var hash = idUser.GetHashCode();
|
||||||
|
hash ^= subject.GetHashCode();
|
||||||
|
hash ^= content.GetHashCode();
|
||||||
|
return hash.ToString("x");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,121 +0,0 @@
|
|||||||
using AsbCloudApp.Exceptions;
|
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Mail;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AsbCloudInfrastructure.Background;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
|
||||||
{
|
|
||||||
|
|
||||||
public class EmailService : IEmailService
|
|
||||||
{
|
|
||||||
private readonly BackgroundWorker backgroundWorker;
|
|
||||||
private readonly bool IsConfigured;
|
|
||||||
private readonly string sender;
|
|
||||||
private readonly string smtpServer;
|
|
||||||
private readonly string smtpPassword;
|
|
||||||
|
|
||||||
public EmailService(BackgroundWorker backgroundWorker, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
sender = configuration.GetValue("email:sender", string.Empty);
|
|
||||||
smtpPassword = configuration.GetValue("email:password", string.Empty);
|
|
||||||
smtpServer = configuration.GetValue("email:smtpServer", string.Empty);
|
|
||||||
|
|
||||||
var configError = string.IsNullOrEmpty(sender) ||
|
|
||||||
string.IsNullOrEmpty(smtpPassword) ||
|
|
||||||
string.IsNullOrEmpty(smtpServer);
|
|
||||||
|
|
||||||
IsConfigured = !configError;
|
|
||||||
|
|
||||||
this.backgroundWorker = backgroundWorker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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)
|
|
||||||
{
|
|
||||||
if (!IsConfigured)
|
|
||||||
{
|
|
||||||
Trace.TraceWarning("smtp is not configured");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var workId = MakeWorkId(addresses, subject, htmlBody);
|
|
||||||
if (!backgroundWorker.Contains(workId))
|
|
||||||
{
|
|
||||||
var workAction = MakeEmailSendWorkAction(addresses, subject, htmlBody);
|
|
||||||
var work = new WorkBase(workId, workAction);
|
|
||||||
backgroundWorker.Push(work);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(IEnumerable<string> addresses, string subject, string htmlBody)
|
|
||||||
{
|
|
||||||
var mailAddresses = new List<MailAddress>();
|
|
||||||
foreach (var address in addresses)
|
|
||||||
{
|
|
||||||
if (MailAddress.TryCreate(address, out MailAddress? mailAddress))
|
|
||||||
mailAddresses.Add(mailAddress);
|
|
||||||
else
|
|
||||||
Trace.TraceWarning($"Mail {address} is not correct.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mailAddresses.Any())
|
|
||||||
throw new ArgumentException($"No valid email found. List:[{string.Join(',', addresses)}]", nameof(addresses));
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(subject))
|
|
||||||
throw new ArgumentInvalidException($"{nameof(subject)} should be set", nameof(subject));
|
|
||||||
|
|
||||||
var workAction = async (string id, IServiceProvider serviceProvider, CancellationToken token) =>
|
|
||||||
{
|
|
||||||
var from = new MailAddress(sender);
|
|
||||||
var message = new MailMessage
|
|
||||||
{
|
|
||||||
From = from
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var mailAddress in mailAddresses)
|
|
||||||
message.To.Add(mailAddress);
|
|
||||||
|
|
||||||
message.BodyEncoding = System.Text.Encoding.UTF8;
|
|
||||||
message.Body = htmlBody;
|
|
||||||
message.Subject = subject;
|
|
||||||
message.IsBodyHtml = true;
|
|
||||||
|
|
||||||
using var client = new SmtpClient(smtpServer);
|
|
||||||
client.EnableSsl = true;
|
|
||||||
client.UseDefaultCredentials = false;
|
|
||||||
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
|
|
||||||
|
|
||||||
await client.SendMailAsync(message, token);
|
|
||||||
Trace.TraceInformation($"Send email to {string.Join(',', addresses)} subj:{subject} html body count {htmlBody.Length}");
|
|
||||||
};
|
|
||||||
return workAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string MakeWorkId(IEnumerable<string> addresses, string subject, string content)
|
|
||||||
{
|
|
||||||
var hash = GetHashCode(addresses);
|
|
||||||
hash ^= subject.GetHashCode();
|
|
||||||
hash ^= content.GetHashCode();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -279,11 +279,15 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
|||||||
|
|
||||||
var beginUTC = gtDate.HasValue
|
var beginUTC = gtDate.HasValue
|
||||||
? gtDate.Value.ToUtcDateTimeOffset(hoursOffset)
|
? gtDate.Value.ToUtcDateTimeOffset(hoursOffset)
|
||||||
: DateTime.Today.AddDays(-1).ToUtcDateTimeOffset(hoursOffset);
|
: db.SubsystemOperationTimes.Min(s => s.DateStart)
|
||||||
|
.DateTime
|
||||||
|
.ToUtcDateTimeOffset(hoursOffset);
|
||||||
|
|
||||||
var endUTC = ltDate.HasValue
|
var endUTC = ltDate.HasValue
|
||||||
? ltDate.Value.ToUtcDateTimeOffset(hoursOffset)
|
? ltDate.Value.ToUtcDateTimeOffset(hoursOffset)
|
||||||
: DateTime.Today.ToUtcDateTimeOffset(hoursOffset);
|
: db.SubsystemOperationTimes.Max(s => s.DateEnd)
|
||||||
|
.DateTime
|
||||||
|
.ToUtcDateTimeOffset(hoursOffset);
|
||||||
|
|
||||||
var telemetryIds = wells
|
var telemetryIds = wells
|
||||||
.Where(w => w.IdTelemetry is not null)
|
.Where(w => w.IdTelemetry is not null)
|
||||||
|
@ -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,35 @@ 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(
|
||||||
{
|
well,
|
||||||
var body = factory.MakeMailBodyForWellFinalDocument(
|
(user.Name ?? user.Surname ?? string.Empty),
|
||||||
well,
|
string.Format(message, documentCategory)
|
||||||
(user.Name ?? user.Surname ?? string.Empty),
|
);
|
||||||
string.Format(message, documentCategory)
|
|
||||||
);
|
|
||||||
|
|
||||||
emailService.EnqueueSend(user.Email, subject, body);
|
await notificationService.NotifyAsync(new NotifyRequest
|
||||||
}
|
{
|
||||||
|
IdUser = user.Id,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = subject,
|
||||||
|
Message = body,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
}, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ using AsbCloudApp.Repositories;
|
|||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudApp.Services.Subsystems;
|
using AsbCloudApp.Services.Subsystems;
|
||||||
using AsbCloudDb.Model;
|
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
@ -16,6 +15,8 @@ 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.IntegrationEvents;
|
||||||
|
using AsbCloudApp.IntegrationEvents.Interfaces;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services
|
namespace AsbCloudInfrastructure.Services
|
||||||
{
|
{
|
||||||
@ -36,7 +37,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository;
|
private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository;
|
||||||
private readonly IGtrRepository gtrRepository;
|
private readonly IGtrRepository gtrRepository;
|
||||||
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
|
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
|
||||||
|
|
||||||
public WellInfoService(
|
public WellInfoService(
|
||||||
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache,
|
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache,
|
||||||
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache,
|
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache,
|
||||||
@ -63,23 +64,18 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
private static async Task WorkAction(string workName, IServiceProvider serviceProvider, CancellationToken token)
|
private static async Task WorkAction(string workName, IServiceProvider serviceProvider, CancellationToken token)
|
||||||
{
|
{
|
||||||
var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
|
||||||
var wellService = serviceProvider.GetRequiredService<IWellService>();
|
var wellService = serviceProvider.GetRequiredService<IWellService>();
|
||||||
var operationsStatService = serviceProvider.GetRequiredService<IOperationsStatService>();
|
var operationsStatService = serviceProvider.GetRequiredService<IOperationsStatService>();
|
||||||
var processMapRepository = serviceProvider.GetRequiredService<IProcessMapPlanRepository>();
|
var processMapRepository = serviceProvider.GetRequiredService<IProcessMapPlanRepository>();
|
||||||
var subsystemOperationTimeService = serviceProvider.GetRequiredService<ISubsystemOperationTimeService>();
|
var subsystemOperationTimeService = serviceProvider.GetRequiredService<ISubsystemOperationTimeService>();
|
||||||
var telemetryDataSaubCache = serviceProvider.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>();
|
var telemetryDataSaubCache = serviceProvider.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>();
|
||||||
|
var messageHub = serviceProvider.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
|
||||||
|
|
||||||
var activeWells = await wellService.GetAsync(new() {IdState = 1}, token);
|
var wells = await wellService.GetAllAsync(token);
|
||||||
|
|
||||||
IEnumerable<int> activeWellsIds = activeWells
|
var wellsIds = wells.Select(w => w.Id);
|
||||||
.Select(w => w.Id);
|
|
||||||
|
|
||||||
var idTelemetries = activeWells
|
var processMapRequests = wellsIds.Select(id => new ProcessMapRequest { IdWell = id });
|
||||||
.Where(w => w.IdTelemetry != null)
|
|
||||||
.Select(t => t.IdTelemetry);
|
|
||||||
|
|
||||||
var processMapRequests = activeWellsIds.Select(id => new ProcessMapRequest { IdWell = id });
|
|
||||||
var processMaps = await processMapRepository.GetProcessMapAsync(processMapRequests, token);
|
var processMaps = await processMapRepository.GetProcessMapAsync(processMapRequests, token);
|
||||||
|
|
||||||
var wellDepthByProcessMap = processMaps
|
var wellDepthByProcessMap = processMaps
|
||||||
@ -90,20 +86,23 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
DepthEnd = g.Max(p => p.DepthEnd)
|
DepthEnd = g.Max(p => p.DepthEnd)
|
||||||
});
|
});
|
||||||
|
|
||||||
var operationsStat = await operationsStatService.GetWellsStatAsync(activeWellsIds, token);
|
var operationsStat = await operationsStatService.GetWellsStatAsync(wellsIds, token);
|
||||||
|
|
||||||
var subsystemStat = await subsystemOperationTimeService.GetStatByActiveWells(activeWellsIds, token);
|
var subsystemStat = await subsystemOperationTimeService
|
||||||
|
.GetStatByActiveWells(wellsIds, token);
|
||||||
|
|
||||||
WellMapInfo = activeWells.Select(well => {
|
WellMapInfo = wells.Select(well => {
|
||||||
var wellMapInfo = well.Adapt<WellMapInfoWithComanies>();
|
var wellMapInfo = well.Adapt<WellMapInfoWithComanies>();
|
||||||
wellMapInfo.IdState = well.IdState;
|
wellMapInfo.IdState = well.IdState;
|
||||||
|
|
||||||
double? currentDepth = null;
|
double? currentDepth = null;
|
||||||
|
|
||||||
|
TelemetryDataSaubDto? lastSaubTelemetry = null;
|
||||||
|
|
||||||
if (well.IdTelemetry.HasValue)
|
if (well.IdTelemetry.HasValue)
|
||||||
{
|
{
|
||||||
wellMapInfo.IdTelemetry = well.IdTelemetry.Value;
|
wellMapInfo.IdTelemetry = well.IdTelemetry.Value;
|
||||||
var lastSaubTelemetry = telemetryDataSaubCache.GetLastOrDefault(well.IdTelemetry.Value);
|
lastSaubTelemetry = telemetryDataSaubCache.GetLastOrDefault(well.IdTelemetry.Value);
|
||||||
if(lastSaubTelemetry is not null)
|
if(lastSaubTelemetry is not null)
|
||||||
{
|
{
|
||||||
currentDepth = lastSaubTelemetry.WellDepth;
|
currentDepth = lastSaubTelemetry.WellDepth;
|
||||||
@ -119,27 +118,54 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.OrderBy(p => p.DepthEnd);
|
.OrderBy(p => p.DepthEnd);
|
||||||
|
|
||||||
int? idSection = wellLastFactSection?.Id;
|
int? idSection = wellLastFactSection?.Id;
|
||||||
ProcessMapPlanDto? welllProcessMap = null;
|
ProcessMapPlanDto? wellProcessMap = null;
|
||||||
|
|
||||||
if (idSection.HasValue)
|
if (idSection.HasValue)
|
||||||
{
|
{
|
||||||
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
|
wellProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
|
||||||
}
|
}
|
||||||
else if(currentDepth.HasValue)
|
else if(currentDepth.HasValue)
|
||||||
{
|
{
|
||||||
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value);
|
wellProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value);
|
||||||
idSection ??= welllProcessMap?.IdWellSectionType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double? planTotalDepth = null;
|
double? planTotalDepth = null;
|
||||||
planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd;
|
planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd;
|
||||||
planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd;
|
planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd;
|
||||||
|
|
||||||
|
wellMapInfo.Section = wellLastFactSection?.Caption;
|
||||||
|
|
||||||
wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start
|
wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start
|
||||||
?? wellOperationsStat?.Total.Plan?.Start;
|
?? wellOperationsStat?.Total.Plan?.Start;
|
||||||
|
|
||||||
wellMapInfo.LastPredictOperationDateEnd = wellOperationsStat?.Total.Plan?.End;
|
wellMapInfo.LastPredictOperationDateEnd = wellOperationsStat?.Total.Plan?.End;
|
||||||
|
|
||||||
|
wellMapInfo.AxialLoad = new()
|
||||||
|
{
|
||||||
|
Plan = wellProcessMap?.AxialLoad.Plan,
|
||||||
|
Fact = lastSaubTelemetry?.AxialLoad
|
||||||
|
};
|
||||||
|
|
||||||
|
wellMapInfo.TopDriveSpeed = new()
|
||||||
|
{
|
||||||
|
Plan = wellProcessMap?.TopDriveSpeed.Plan,
|
||||||
|
Fact = lastSaubTelemetry?.RotorSpeed
|
||||||
|
};
|
||||||
|
|
||||||
|
wellMapInfo.TopDriveTorque = new()
|
||||||
|
{
|
||||||
|
Plan = wellProcessMap?.TopDriveTorque.Plan,
|
||||||
|
Fact = lastSaubTelemetry?.RotorTorque
|
||||||
|
};
|
||||||
|
|
||||||
|
wellMapInfo.Pressure = new()
|
||||||
|
{
|
||||||
|
Plan = wellProcessMap?.Pressure.Plan,
|
||||||
|
Fact = lastSaubTelemetry?.Pressure
|
||||||
|
};
|
||||||
|
|
||||||
|
wellMapInfo.PressureSp = lastSaubTelemetry?.PressureSp;
|
||||||
|
|
||||||
wellMapInfo.WellDepth = new()
|
wellMapInfo.WellDepth = new()
|
||||||
{
|
{
|
||||||
Plan = planTotalDepth,
|
Plan = planTotalDepth,
|
||||||
@ -148,7 +174,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
wellMapInfo.ROP = new()
|
wellMapInfo.ROP = new()
|
||||||
{
|
{
|
||||||
Plan = welllProcessMap?.RopPlan,
|
Plan = wellProcessMap?.RopPlan,
|
||||||
Fact = wellOperationsStat?.Total.Fact?.Rop,
|
Fact = wellOperationsStat?.Total.Fact?.Rop,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -167,6 +193,11 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
return wellMapInfo;
|
return wellMapInfo;
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
|
var updateWellInfoEventTasks = wellsIds.Select(idWell =>
|
||||||
|
messageHub.HandleAsync(new UpdateWellInfoEvent(idWell), token));
|
||||||
|
|
||||||
|
await Task.WhenAll(updateWellInfoEventTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WellMapInfoWithTelemetryStat Convert(WellMapInfoWithComanies wellInfo)
|
private WellMapInfoWithTelemetryStat Convert(WellMapInfoWithComanies wellInfo)
|
||||||
|
@ -92,7 +92,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
Longitude = gCluster.Key.Longitude ?? gDeposit.Key.Longitude,
|
Longitude = gCluster.Key.Longitude ?? gDeposit.Key.Longitude,
|
||||||
Wells = gCluster.Select(well =>
|
Wells = gCluster.Select(well =>
|
||||||
{
|
{
|
||||||
var dto = wellInfoService.FirstOrDefault(w => w.Id == well.Id);
|
var dto = wellInfoService.FirstOrDefault(w => w.Id == well.Id && well.IdState == 1);
|
||||||
dto ??= well.Adapt<WellMapInfoWithTelemetryStat>();
|
dto ??= well.Adapt<WellMapInfoWithTelemetryStat>();
|
||||||
dto.Latitude ??= gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
|
dto.Latitude ??= gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
|
||||||
dto.Longitude ??= gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
|
dto.Longitude ??= gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
|
||||||
|
@ -38,8 +38,14 @@ namespace AsbCloudInfrastructure
|
|||||||
backgroundWorker.Push(LimitingParameterCalcWorkFactory.MakeWork());
|
backgroundWorker.Push(LimitingParameterCalcWorkFactory.MakeWork());
|
||||||
backgroundWorker.Push(MakeMemoryMonitoringWork());
|
backgroundWorker.Push(MakeMemoryMonitoringWork());
|
||||||
|
|
||||||
|
var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>();
|
||||||
|
|
||||||
Task.Delay(1_000)
|
Task.Delay(1_000)
|
||||||
.ContinueWith(async (_) => await backgroundWorker.StartAsync(CancellationToken.None));
|
.ContinueWith(async (_) =>
|
||||||
|
{
|
||||||
|
await backgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
await notificationBackgroundWorker.StartAsync(CancellationToken.None);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static WorkPeriodic MakeMemoryMonitoringWork()
|
static WorkPeriodic MakeMemoryMonitoringWork()
|
||||||
|
@ -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>()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -6,6 +7,7 @@ using AsbCloudApp.Exceptions;
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -17,50 +19,36 @@ namespace AsbCloudWebApi.Controllers;
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
|
[Obsolete("Это тестовый контроллер, его нельзя использовать на фронте.")]
|
||||||
public class NotificationController : ControllerBase
|
public class NotificationController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly NotificationService notificationService;
|
private readonly NotificationService notificationService;
|
||||||
private readonly INotificationRepository notificationRepository;
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
private readonly NotificationPublisher notificationPublisher;
|
||||||
|
|
||||||
public NotificationController(NotificationService notificationService,
|
public NotificationController(NotificationService notificationService,
|
||||||
INotificationRepository notificationRepository)
|
INotificationRepository notificationRepository,
|
||||||
|
NotificationPublisher notificationPublisher)
|
||||||
{
|
{
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
this.notificationRepository = notificationRepository;
|
this.notificationRepository = notificationRepository;
|
||||||
|
this.notificationPublisher = notificationPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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="idNotificationTransport">Id типа доставки уведомления. Допустимое значение: 0</param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
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: 0, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0")]
|
|
||||||
int idNotificationTransport,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
await notificationService.NotifyAsync(idUser,
|
await notificationService.NotifyAsync(request, cancellationToken);
|
||||||
idNotificationCategory,
|
|
||||||
title,
|
|
||||||
message,
|
|
||||||
idNotificationTransport,
|
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Обновление уведомления
|
/// Обновление уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -73,13 +61,20 @@ public class NotificationController : ControllerBase
|
|||||||
[Required] bool isRead,
|
[Required] bool isRead,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await notificationService.UpdateNotificationAsync(idNotification,
|
var idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
await notificationService.UpdateAsync(idNotification,
|
||||||
isRead,
|
isRead,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
|
await notificationPublisher.PublishCountUnreadAsync(idUser.Value, cancellationToken);
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение уведомления по Id
|
/// Получение уведомления по Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -96,12 +91,12 @@ public class NotificationController : ControllerBase
|
|||||||
if (notification is null)
|
if (notification is null)
|
||||||
{
|
{
|
||||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(idNotification),
|
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(idNotification),
|
||||||
"Уведомление не найдено"));
|
"Уведомление не найдено"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(notification);
|
return Ok(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение списка уведомлений
|
/// Получение списка уведомлений
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -117,7 +112,7 @@ public class NotificationController : ControllerBase
|
|||||||
|
|
||||||
if (!idUser.HasValue)
|
if (!idUser.HasValue)
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await notificationRepository.GetNotificationsAsync(idUser.Value,
|
var result = await notificationRepository.GetNotificationsAsync(idUser.Value,
|
||||||
request,
|
request,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
@ -140,4 +135,19 @@ public class NotificationController : ControllerBase
|
|||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Параметры запроса</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete]
|
||||||
|
public async Task<IActionResult> DeleteAsync(NotificationDeleteRequest request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await notificationRepository.DeleteAsync(request, cancellationToken);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
@ -32,7 +32,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
IWellOperationImportService wellOperationImportService,
|
IWellOperationImportService wellOperationImportService,
|
||||||
IUserRepository userRepository)
|
IUserRepository userRepository)
|
||||||
{
|
{
|
||||||
this.operationRepository = operationService;
|
this.operationRepository = operationRepository;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.wellOperationImportService = wellOperationImportService;
|
this.wellOperationImportService = wellOperationImportService;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
@ -218,7 +218,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
|
|
||||||
var result = await operationRepository.InsertRangeAsync(values, token)
|
var result = await operationRepository.InsertRangeAsync(values, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ using AsbCloudApp.Repositories;
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
@ -12,8 +11,13 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.IntegrationEvents;
|
||||||
|
using AsbCloudApp.IntegrationEvents.Interfaces;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudInfrastructure.Services.Email;
|
||||||
|
using AsbCloudWebApi.SignalR;
|
||||||
using AsbCloudWebApi.SignalR.Services;
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi.Any;
|
||||||
|
|
||||||
namespace AsbCloudWebApi
|
namespace AsbCloudWebApi
|
||||||
@ -139,6 +143,12 @@ 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>();
|
||||||
|
|
||||||
|
services.AddTransient<NotificationPublisher>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddIntegrationEvents(this IServiceCollection services) => services
|
||||||
|
.AddTransient<IIntegrationEventHandler<UpdateWellInfoEvent>, WellInfoHub>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
AsbCloudWebApi/SignalR/Messages/NotificationMessage.cs
Normal file
11
AsbCloudWebApi/SignalR/Messages/NotificationMessage.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR.Messages;
|
||||||
|
|
||||||
|
public class NotificationMessage
|
||||||
|
{
|
||||||
|
public IEnumerable<NotificationDto>? Notifications { get; set; }
|
||||||
|
|
||||||
|
public int CountUnread { get; set; }
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Requests;
|
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
using AsbCloudWebApi.SignalR.Services;
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -14,12 +13,15 @@ public class NotificationHub : BaseHub
|
|||||||
{
|
{
|
||||||
private readonly ConnectionManagerService connectionManagerService;
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
private readonly NotificationService notificationService;
|
private readonly NotificationService notificationService;
|
||||||
|
private readonly NotificationPublisher notificationPublisher;
|
||||||
|
|
||||||
public NotificationHub(ConnectionManagerService connectionManagerService,
|
public NotificationHub(ConnectionManagerService connectionManagerService,
|
||||||
NotificationService notificationService)
|
NotificationService notificationService,
|
||||||
|
NotificationPublisher notificationPublisher)
|
||||||
{
|
{
|
||||||
this.connectionManagerService = connectionManagerService;
|
this.connectionManagerService = connectionManagerService;
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
|
this.notificationPublisher = notificationPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnConnectedAsync()
|
public override async Task OnConnectedAsync()
|
||||||
@ -35,9 +37,10 @@ public class NotificationHub : BaseHub
|
|||||||
|
|
||||||
await base.OnConnectedAsync();
|
await base.OnConnectedAsync();
|
||||||
|
|
||||||
await notificationService.ResendNotificationAsync(idUser.Value,
|
await notificationPublisher.PublishCountUnreadAsync(idUser.Value, CancellationToken.None);
|
||||||
new NotificationRequest { IsSent = false, IdTransportType = 0},
|
|
||||||
CancellationToken.None);
|
await notificationService.RenotifyAsync(idUser.Value,
|
||||||
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnDisconnectedAsync(Exception? exception)
|
public override async Task OnDisconnectedAsync(Exception? exception)
|
||||||
|
77
AsbCloudWebApi/SignalR/Services/NotificationPublisher.cs
Normal file
77
AsbCloudWebApi/SignalR/Services/NotificationPublisher.cs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudWebApi.SignalR.Messages;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR.Services;
|
||||||
|
|
||||||
|
public class NotificationPublisher
|
||||||
|
{
|
||||||
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
|
private readonly IHubContext<NotificationHub> notificationHubContext;
|
||||||
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
|
||||||
|
public NotificationPublisher(ConnectionManagerService connectionManagerService,
|
||||||
|
IHubContext<NotificationHub> notificationHubContext,
|
||||||
|
INotificationRepository notificationRepository)
|
||||||
|
{
|
||||||
|
this.connectionManagerService = connectionManagerService;
|
||||||
|
this.notificationHubContext = notificationHubContext;
|
||||||
|
this.notificationRepository = notificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PublishAsync(IGrouping<int, NotificationDto> groupedNotifications, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
const int idTransportType = 0;
|
||||||
|
|
||||||
|
var connectionId = connectionManagerService.GetConnectionIdByUserId(groupedNotifications.Key);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(connectionId))
|
||||||
|
{
|
||||||
|
foreach (var notification in groupedNotifications)
|
||||||
|
{
|
||||||
|
notification.SentDate = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notifications = groupedNotifications.Select(n => n);
|
||||||
|
|
||||||
|
await notificationRepository.UpdateRangeAsync(notifications,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
await PublishMessageAsync(connectionId, new NotificationMessage
|
||||||
|
{
|
||||||
|
Notifications = notifications,
|
||||||
|
CountUnread = await notificationRepository.GetUnreadCountAsync(groupedNotifications.Key,
|
||||||
|
idTransportType,
|
||||||
|
cancellationToken)
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PublishCountUnreadAsync(int idUser, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var connectionId = connectionManagerService.GetConnectionIdByUserId(idUser);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(connectionId))
|
||||||
|
{
|
||||||
|
await PublishMessageAsync(connectionId, new NotificationMessage
|
||||||
|
{
|
||||||
|
CountUnread = await notificationRepository.GetUnreadCountAsync(idUser, 0,
|
||||||
|
cancellationToken)
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PublishMessageAsync(string connectionId, NotificationMessage message,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await notificationHubContext.Clients.Client(connectionId)
|
||||||
|
.SendAsync("receiveNotifications",
|
||||||
|
message,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
@ -5,48 +5,52 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.SignalR.Services;
|
namespace AsbCloudWebApi.SignalR.Services;
|
||||||
|
|
||||||
public class SignalRNotificationTransportService : INotificationTransportService
|
public class SignalRNotificationTransportService : INotificationTransportService
|
||||||
{
|
{
|
||||||
private readonly ConnectionManagerService connectionManagerService;
|
private readonly NotificationBackgroundWorker backgroundWorker;
|
||||||
private readonly IHubContext<NotificationHub> notificationHubContext;
|
|
||||||
|
|
||||||
public SignalRNotificationTransportService(ConnectionManagerService connectionManagerService,
|
public SignalRNotificationTransportService(NotificationBackgroundWorker backgroundWorker)
|
||||||
IHubContext<NotificationHub> notificationHubContext)
|
|
||||||
{
|
{
|
||||||
this.connectionManagerService = connectionManagerService;
|
this.backgroundWorker = backgroundWorker;
|
||||||
this.notificationHubContext = notificationHubContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IdTransportType => 0;
|
public int IdTransportType => 0;
|
||||||
|
|
||||||
public async Task SendAsync(NotificationDto notification,
|
public Task SendAsync(NotificationDto notification,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken) => SendRangeAsync(new[] { notification }, cancellationToken);
|
||||||
{
|
|
||||||
const string method = "receiveNotifications";
|
|
||||||
|
|
||||||
var connectionId = connectionManagerService.GetConnectionIdByUserId(notification.IdUser);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(connectionId))
|
|
||||||
{
|
|
||||||
notification.SentDate = DateTime.UtcNow;
|
|
||||||
|
|
||||||
await notificationHubContext.Clients.Client(connectionId)
|
|
||||||
.SendAsync(method,
|
|
||||||
notification,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task SendRangeAsync(IEnumerable<NotificationDto> notifications,
|
public Task SendRangeAsync(IEnumerable<NotificationDto> notifications,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tasks = notifications
|
var workId = HashCode.Combine(notifications.Select(n => n.Id)).ToString("x");
|
||||||
.Select(notification => SendAsync(notification, cancellationToken));
|
|
||||||
|
|
||||||
return Task.WhenAll(tasks);
|
if (backgroundWorker.Contains(workId))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var workAction = MakeSignalRSendWorkAction(notifications);
|
||||||
|
var work = new WorkBase(workId, workAction);
|
||||||
|
backgroundWorker.Push(work);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func<string, IServiceProvider, CancellationToken, Task> MakeSignalRSendWorkAction(IEnumerable<NotificationDto> notifications)
|
||||||
|
{
|
||||||
|
return async (_, serviceProvider, cancellationToken) =>
|
||||||
|
{
|
||||||
|
var notificationPublisher = serviceProvider.GetRequiredService<NotificationPublisher>();
|
||||||
|
|
||||||
|
var groupedNotificationsByUsers = notifications.GroupBy(n => n.IdUser);
|
||||||
|
|
||||||
|
foreach (var groupedNotificationByUser in groupedNotificationsByUsers)
|
||||||
|
{
|
||||||
|
await notificationPublisher.PublishAsync(groupedNotificationByUser, cancellationToken);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
53
AsbCloudWebApi/SignalR/WellInfoHub.cs
Normal file
53
AsbCloudWebApi/SignalR/WellInfoHub.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.IntegrationEvents;
|
||||||
|
using AsbCloudApp.IntegrationEvents.Interfaces;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using AsbCloudInfrastructure.Services;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR;
|
||||||
|
|
||||||
|
public class WellInfoHub : BaseHub, IIntegrationEventHandler<UpdateWellInfoEvent>
|
||||||
|
{
|
||||||
|
private readonly IHubContext<WellInfoHub> hubContext;
|
||||||
|
private readonly IWellService wellService;
|
||||||
|
private readonly WellInfoService wellInfoService;
|
||||||
|
|
||||||
|
public WellInfoHub(IHubContext<WellInfoHub> hubContext,
|
||||||
|
IWellService wellService,
|
||||||
|
WellInfoService wellInfoService)
|
||||||
|
{
|
||||||
|
this.hubContext = hubContext;
|
||||||
|
this.wellService = wellService;
|
||||||
|
this.wellInfoService = wellInfoService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task AddToGroup(string groupName)
|
||||||
|
{
|
||||||
|
var idWell = int.Parse(groupName.Split('_')[2]);
|
||||||
|
|
||||||
|
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
|
||||||
|
|
||||||
|
await HandleAsync(new UpdateWellInfoEvent(idWell), CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleAsync(UpdateWellInfoEvent integrationEvent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
const string method = "update_well_info";
|
||||||
|
|
||||||
|
var well = await wellService.GetOrDefaultAsync(integrationEvent.IdWell, cancellationToken);
|
||||||
|
|
||||||
|
if(well is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var wellInfo = wellInfoService.FirstOrDefault(w => w.Id == well.Id);
|
||||||
|
|
||||||
|
await hubContext.Clients.Group($"well_info_{integrationEvent.IdWell}")
|
||||||
|
.SendAsync(method, new
|
||||||
|
{
|
||||||
|
Well = well,
|
||||||
|
WellInfo = wellInfo
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,8 @@ namespace AsbCloudWebApi
|
|||||||
|
|
||||||
services.AddNotificationTransportServices();
|
services.AddNotificationTransportServices();
|
||||||
|
|
||||||
|
services.AddIntegrationEvents();
|
||||||
|
|
||||||
services.AddJWTAuthentication();
|
services.AddJWTAuthentication();
|
||||||
|
|
||||||
services.AddSignalR()
|
services.AddSignalR()
|
||||||
@ -151,6 +153,7 @@ namespace AsbCloudWebApi
|
|||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
|
endpoints.MapHub<WellInfoHub>("/hubs/wellInfo");
|
||||||
endpoints.MapHub<NotificationHub>("/hubs/notifications");
|
endpoints.MapHub<NotificationHub>("/hubs/notifications");
|
||||||
endpoints.MapHub<TelemetryHub>("/hubs/telemetry");
|
endpoints.MapHub<TelemetryHub>("/hubs/telemetry");
|
||||||
endpoints.MapHub<ReportsHub>("/hubs/reports");
|
endpoints.MapHub<ReportsHub>("/hubs/reports");
|
||||||
|
@ -10,7 +10,7 @@ internal class Program
|
|||||||
{
|
{
|
||||||
var connectionBuilder = new HubConnectionBuilder();
|
var connectionBuilder = new HubConnectionBuilder();
|
||||||
var connection = connectionBuilder
|
var connection = connectionBuilder
|
||||||
.WithUrl("http://localhost:5000/hubs/notifications", connectionOptions => {
|
.WithUrl("http://localhost:5000/hubs/limitingParameters", connectionOptions => {
|
||||||
connectionOptions.AccessTokenProvider = AccessTokenProvider;
|
connectionOptions.AccessTokenProvider = AccessTokenProvider;
|
||||||
})
|
})
|
||||||
.WithAutomaticReconnect()
|
.WithAutomaticReconnect()
|
||||||
@ -26,9 +26,9 @@ internal class Program
|
|||||||
connection.StartAsync().Wait();
|
connection.StartAsync().Wait();
|
||||||
|
|
||||||
//Console.WriteLine("OnConnected");
|
//Console.WriteLine("OnConnected");
|
||||||
//connection.SendCoreAsync("OnConnected", new object[] { }, CancellationToken.None).Wait();
|
connection.SendCoreAsync("OnConnectedAsync", new object[] { 1 }, CancellationToken.None).Wait();
|
||||||
|
|
||||||
var subsction = connection.On<object>("receiveNotifications", (str1) => {
|
var subsction = connection.On<object>("well_info_update", (str1) => {
|
||||||
Console.WriteLine(str1);
|
Console.WriteLine(str1);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user