forked from ddrilling/AsbCloudServer
Merge branch 'dev' into fix/trim-subsystem-operation-time-data
This commit is contained in:
commit
68d2675d9a
@ -13,5 +13,15 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Caption { get; set; } = null!;
|
public string Caption { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Порядок
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Является ли контактом
|
||||||
|
/// </summary>
|
||||||
|
public bool IsContact { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
AsbCloudApp/Data/NotificationCategoryDto.cs
Normal file
17
AsbCloudApp/Data/NotificationCategoryDto.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace AsbCloudApp.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DTO категории уведомления
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationCategoryDto : IId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id категории
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название категории
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
}
|
75
AsbCloudApp/Data/NotificationDto.cs
Normal file
75
AsbCloudApp/Data/NotificationDto.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DTO уведомления
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationDto : IId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id уведомления
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id получателя уведомления
|
||||||
|
/// </summary>
|
||||||
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id категории уведомления
|
||||||
|
/// </summary>
|
||||||
|
public int IdNotificationCategory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заголовок уведомления
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сообщение уведомления
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата отправки уведомления
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? SentDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата прочтения уведомления
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ReadDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Состояние уведомления
|
||||||
|
/// 0 - Зарегистрировано,
|
||||||
|
/// 1 - Отправлено,
|
||||||
|
/// 2 - Прочитано
|
||||||
|
/// </summary>
|
||||||
|
public int IdState
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (SentDate is not null && ReadDate is not null)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (SentDate is not null)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id типа доставки уведомления
|
||||||
|
/// 0 - SignalR
|
||||||
|
/// </summary>
|
||||||
|
public int IdTransportType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DTO категории уведомления
|
||||||
|
/// </summary>
|
||||||
|
public NotificationCategoryDto NotificationCategory { get; set; } = null!;
|
||||||
|
}
|
@ -62,8 +62,11 @@ namespace AsbCloudApp.Data.User
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id состояния пользователя
|
/// Id состояния пользователя
|
||||||
|
/// 0 - не активен,
|
||||||
|
/// 1 - активен,
|
||||||
|
/// 2 - заблокирован
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public short? IdState { get; set; }
|
public short IdState { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DTO компании
|
/// DTO компании
|
||||||
|
34
AsbCloudApp/Repositories/INotificationRepository.cs
Normal file
34
AsbCloudApp/Repositories/INotificationRepository.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Repositories;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Репозиторий для уведомлений
|
||||||
|
/// </summary>
|
||||||
|
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>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
|
||||||
|
NotificationRequest request,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
}
|
17
AsbCloudApp/Requests/NotificationRequest.cs
Normal file
17
AsbCloudApp/Requests/NotificationRequest.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace AsbCloudApp.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры запроса для получения уведомлений
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationRequest : RequestBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получение отправленных/не отправленных уведомлений
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsSent { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id типа доставки уведомления
|
||||||
|
/// </summary>
|
||||||
|
public int? IdTransportType { get; set; }
|
||||||
|
}
|
@ -19,15 +19,15 @@ namespace AsbCloudApp.Requests
|
|||||||
public DateTime? LtDate { get; set; }
|
public DateTime? LtDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// фильтр по максимальной глубине скважины
|
/// фильтр. Больше или равно глубины скважины на начало операции.
|
||||||
/// </summary>
|
|
||||||
public double? LeDepth { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// фильтр по минимальной глубине скважины
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double? GeDepth { get; set; }
|
public double? GeDepth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// фильтр. Меньше или равно глубины скважины на конец операции.
|
||||||
|
/// </summary>
|
||||||
|
public double? LeDepth { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// фильтр по списку id категорий операции
|
/// фильтр по списку id категорий операции
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -22,9 +22,10 @@ namespace AsbCloudApp.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение типов контаков
|
/// Получение типов контаков
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="idWell">ключ скважины</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<CompanyTypeDto>> GetTypesAsync(CancellationToken token);
|
Task<IEnumerable<CompanyTypeDto>> GetTypesAsync(int idWell, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Обновление контактов по ключу скважины, типу контакта и ключам пользователей
|
/// Обновление контактов по ключу скважины, типу контакта и ключам пользователей
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services.Notifications;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс для отправителя уведомлений
|
||||||
|
/// </summary>
|
||||||
|
public interface INotificationTransportService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id типа доставки уведомления
|
||||||
|
/// </summary>
|
||||||
|
int IdTransportType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Отправка одного уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notification"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task SendAsync(NotificationDto notification,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Отправка нескольких уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notifications"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task SendRangeAsync(IEnumerable<NotificationDto> notifications,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
}
|
143
AsbCloudApp/Services/Notifications/NotificationService.cs
Normal file
143
AsbCloudApp/Services/Notifications/NotificationService.cs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services.Notifications;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для работы с уведомлениями
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationService
|
||||||
|
{
|
||||||
|
private readonly ICrudRepository<NotificationCategoryDto> notificationCategoryRepository;
|
||||||
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
private readonly IEnumerable<INotificationTransportService> notificationTransportServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для работы с уведомлениями
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notificationCategoryRepository"></param>
|
||||||
|
/// <param name="notificationRepository"></param>
|
||||||
|
/// <param name="notificationTransportServices"></param>
|
||||||
|
public NotificationService(ICrudRepository<NotificationCategoryDto> notificationCategoryRepository,
|
||||||
|
INotificationRepository notificationRepository,
|
||||||
|
IEnumerable<INotificationTransportService> notificationTransportServices)
|
||||||
|
{
|
||||||
|
this.notificationCategoryRepository = notificationCategoryRepository;
|
||||||
|
this.notificationRepository = notificationRepository;
|
||||||
|
this.notificationTransportServices = notificationTransportServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Отправка нового уведомления
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="idNotificationCategory"></param>
|
||||||
|
/// <param name="title"></param>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="idTransportType"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task NotifyAsync(int idUser,
|
||||||
|
int idNotificationCategory,
|
||||||
|
string title,
|
||||||
|
string message,
|
||||||
|
int idTransportType,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var notificationCategory = await notificationCategoryRepository
|
||||||
|
.GetOrDefaultAsync(idNotificationCategory, cancellationToken)
|
||||||
|
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(idNotificationCategory));
|
||||||
|
|
||||||
|
var notification = new NotificationDto()
|
||||||
|
{
|
||||||
|
IdUser = idUser,
|
||||||
|
IdNotificationCategory = idNotificationCategory,
|
||||||
|
Title = title,
|
||||||
|
Message = message,
|
||||||
|
IdTransportType = idTransportType
|
||||||
|
};
|
||||||
|
|
||||||
|
notification.Id = await notificationRepository.InsertAsync(notification,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
notification.NotificationCategory = notificationCategory;
|
||||||
|
|
||||||
|
var notificationTransportService = GetNotificationTransportService(idTransportType);
|
||||||
|
|
||||||
|
await notificationTransportService.SendAsync(notification, cancellationToken);
|
||||||
|
|
||||||
|
await notificationRepository.UpdateAsync(notification,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление уведомления
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idNotification"></param>
|
||||||
|
/// <param name="isRead"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task UpdateNotificationAsync(int idNotification,
|
||||||
|
bool isRead,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var notification = await notificationRepository.GetOrDefaultAsync(idNotification,
|
||||||
|
cancellationToken)
|
||||||
|
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
||||||
|
|
||||||
|
if (isRead)
|
||||||
|
{
|
||||||
|
if (notification.SentDate == null)
|
||||||
|
throw new ArgumentInvalidException("Уведомление не может быть прочитано", nameof(isRead));
|
||||||
|
|
||||||
|
notification.SentDate = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
await notificationRepository.UpdateAsync(notification,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Отправка уведомлений, которые не были отправлены
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task ResendNotificationAsync(int idUser,
|
||||||
|
NotificationRequest request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!request.IdTransportType.HasValue)
|
||||||
|
throw new ArgumentInvalidException("Id типа доставки уведомления должен иметь значение",
|
||||||
|
nameof(request.IdTransportType));
|
||||||
|
|
||||||
|
var result = await notificationRepository.GetNotificationsAsync(idUser,
|
||||||
|
request,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
var notificationTransportService = GetNotificationTransportService(request.IdTransportType.Value);
|
||||||
|
|
||||||
|
await notificationTransportService.SendRangeAsync(result.Items,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
await notificationRepository.UpdateRangeAsync(result.Items,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private INotificationTransportService GetNotificationTransportService(int idTransportType)
|
||||||
|
{
|
||||||
|
var notificationTransportService = notificationTransportServices
|
||||||
|
.FirstOrDefault(s => s.IdTransportType == idTransportType)
|
||||||
|
?? throw new ArgumentInvalidException("Доставщик уведомлений не найден", nameof(idTransportType));
|
||||||
|
|
||||||
|
return notificationTransportService;
|
||||||
|
}
|
||||||
|
}
|
8226
AsbCloudDb/Migrations/20230711130529_Update_IdState_For_User.Designer.cs
generated
Normal file
8226
AsbCloudDb/Migrations/20230711130529_Update_IdState_For_User.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,72 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Update_IdState_For_User : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_user",
|
||||||
|
keyColumn: "state",
|
||||||
|
keyValue: null,
|
||||||
|
column: "state",
|
||||||
|
value: (short)1);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<short>(
|
||||||
|
name: "state",
|
||||||
|
table: "t_user",
|
||||||
|
type: "smallint",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: (short)0,
|
||||||
|
comment: "состояние:\n0 - не активен, \n1 - активен, \n2 - заблокирован",
|
||||||
|
oldClrType: typeof(short),
|
||||||
|
oldType: "smallint",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "состояние:\n100 - удален");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "id_category",
|
||||||
|
table: "t_help_page",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
comment: "Id категории файла",
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "integer",
|
||||||
|
oldComment: "id категории файла");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<short>(
|
||||||
|
name: "state",
|
||||||
|
table: "t_user",
|
||||||
|
type: "smallint",
|
||||||
|
nullable: true,
|
||||||
|
comment: "состояние:\n100 - удален",
|
||||||
|
oldClrType: typeof(short),
|
||||||
|
oldType: "smallint",
|
||||||
|
oldComment: "состояние:\n0 - не активен, \n1 - активен, \n2 - заблокирован");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "id_category",
|
||||||
|
table: "t_help_page",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
comment: "id категории файла",
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "integer",
|
||||||
|
oldComment: "Id категории файла");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_user",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 1,
|
||||||
|
column: "state",
|
||||||
|
value: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8341
AsbCloudDb/Migrations/20230711130624_Add_Notification.Designer.cs
generated
Normal file
8341
AsbCloudDb/Migrations/20230711130624_Add_Notification.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
85
AsbCloudDb/Migrations/20230711130624_Add_Notification.cs
Normal file
85
AsbCloudDb/Migrations/20230711130624_Add_Notification.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Notification : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "t_notification_category",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
name = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_t_notification_category", x => x.id);
|
||||||
|
},
|
||||||
|
comment: "Категории уведомлений");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "t_notification",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
id_user = table.Column<int>(type: "integer", nullable: false, comment: "Id получателя"),
|
||||||
|
id_notification_category = table.Column<int>(type: "integer", nullable: false, comment: "Id категории уведомления"),
|
||||||
|
title = table.Column<string>(type: "text", nullable: false, comment: "Заголовок уведомления"),
|
||||||
|
message = table.Column<string>(type: "text", nullable: false, comment: "Сообщение уведомления"),
|
||||||
|
time_to_life = table.Column<TimeSpan>(type: "interval", nullable: false, comment: "Время жизни уведомления"),
|
||||||
|
sent_date = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "Дата отправки уведомления"),
|
||||||
|
notification_state = table.Column<string>(type: "text", nullable: false, comment: "Состояние уведомления"),
|
||||||
|
notification_transport = table.Column<string>(type: "text", nullable: false, comment: "Метод доставки уведомления")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_t_notification", x => x.id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_notification_t_notification_category_id_notification_cate~",
|
||||||
|
column: x => x.id_notification_category,
|
||||||
|
principalTable: "t_notification_category",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_notification_t_user_id_user",
|
||||||
|
column: x => x.id_user,
|
||||||
|
principalTable: "t_user",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
},
|
||||||
|
comment: "Уведомления");
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "t_notification_category",
|
||||||
|
columns: new[] { "id", "name" },
|
||||||
|
values: new object[] { 1, "Системные уведомления" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_notification_id_notification_category",
|
||||||
|
table: "t_notification",
|
||||||
|
column: "id_notification_category");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_notification_id_user",
|
||||||
|
table: "t_notification",
|
||||||
|
column: "id_user");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "t_notification");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "t_notification_category");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8232
AsbCloudDb/Migrations/20230713050032_Add_Order_For_CompanyType.Designer.cs
generated
Normal file
8232
AsbCloudDb/Migrations/20230713050032_Add_Order_For_CompanyType.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,47 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Order_For_CompanyType : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "order",
|
||||||
|
table: "t_company_type",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 1,
|
||||||
|
column: "order",
|
||||||
|
value: 1);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 2,
|
||||||
|
column: "order",
|
||||||
|
value: 2);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 5,
|
||||||
|
column: "order",
|
||||||
|
value: 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "order",
|
||||||
|
table: "t_company_type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8334
AsbCloudDb/Migrations/20230713085928_Update_Notification.Designer.cs
generated
Normal file
8334
AsbCloudDb/Migrations/20230713085928_Update_Notification.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
95
AsbCloudDb/Migrations/20230713085928_Update_Notification.cs
Normal file
95
AsbCloudDb/Migrations/20230713085928_Update_Notification.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Update_Notification : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "notification_state",
|
||||||
|
table: "t_notification");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "notification_transport",
|
||||||
|
table: "t_notification");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "time_to_life",
|
||||||
|
table: "t_notification");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "id_transport_type",
|
||||||
|
table: "t_notification",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
comment: "Id типа доставки уведомления");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "read_date",
|
||||||
|
table: "t_notification",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Дата прочтения уведомления");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "id_category",
|
||||||
|
table: "t_help_page",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
comment: "Id категории файла",
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "integer",
|
||||||
|
oldComment: "id категории файла");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "id_transport_type",
|
||||||
|
table: "t_notification");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "read_date",
|
||||||
|
table: "t_notification");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "notification_state",
|
||||||
|
table: "t_notification",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
comment: "Состояние уведомления");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "notification_transport",
|
||||||
|
table: "t_notification",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
comment: "Метод доставки уведомления");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<TimeSpan>(
|
||||||
|
name: "time_to_life",
|
||||||
|
table: "t_notification",
|
||||||
|
type: "interval",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new TimeSpan(0, 0, 0, 0, 0),
|
||||||
|
comment: "Время жизни уведомления");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "id_category",
|
||||||
|
table: "t_help_page",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
comment: "id категории файла",
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "integer",
|
||||||
|
oldComment: "Id категории файла");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -122,6 +122,10 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Property<bool>("IsContact")
|
b.Property<bool>("IsContact")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("order");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("t_company_type");
|
b.ToTable("t_company_type");
|
||||||
@ -131,19 +135,22 @@ namespace AsbCloudDb.Migrations
|
|||||||
{
|
{
|
||||||
Id = 1,
|
Id = 1,
|
||||||
Caption = "Недрапользователь",
|
Caption = "Недрапользователь",
|
||||||
IsContact = false
|
IsContact = false,
|
||||||
|
Order = 1
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 2,
|
Id = 2,
|
||||||
Caption = "Буровой подрядчик",
|
Caption = "Буровой подрядчик",
|
||||||
IsContact = false
|
IsContact = false,
|
||||||
|
Order = 2
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 3,
|
Id = 3,
|
||||||
Caption = "Сервис автоматизации бурения",
|
Caption = "Сервис автоматизации бурения",
|
||||||
IsContact = false
|
IsContact = false,
|
||||||
|
Order = 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -989,7 +996,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Property<int>("IdCategory")
|
b.Property<int>("IdCategory")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("id_category")
|
.HasColumnName("id_category")
|
||||||
.HasComment("id категории файла");
|
.HasComment("Id категории файла");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
@ -1152,6 +1159,91 @@ namespace AsbCloudDb.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Notification", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("IdNotificationCategory")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_notification_category")
|
||||||
|
.HasComment("Id категории уведомления");
|
||||||
|
|
||||||
|
b.Property<int>("IdTransportType")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_transport_type")
|
||||||
|
.HasComment("Id типа доставки уведомления");
|
||||||
|
|
||||||
|
b.Property<int>("IdUser")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_user")
|
||||||
|
.HasComment("Id получателя");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("message")
|
||||||
|
.HasComment("Сообщение уведомления");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ReadDate")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("read_date")
|
||||||
|
.HasComment("Дата прочтения уведомления");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("SentDate")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("sent_date")
|
||||||
|
.HasComment("Дата отправки уведомления");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasComment("Заголовок уведомления");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("IdNotificationCategory");
|
||||||
|
|
||||||
|
b.HasIndex("IdUser");
|
||||||
|
|
||||||
|
b.ToTable("t_notification");
|
||||||
|
|
||||||
|
b.HasComment("Уведомления");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.NotificationCategory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("t_notification_category");
|
||||||
|
|
||||||
|
b.HasComment("Категории уведомлений");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Name = "Системные уведомления"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.OperationValue", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.OperationValue", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -4761,10 +4853,10 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("id_company");
|
.HasColumnName("id_company");
|
||||||
|
|
||||||
b.Property<short?>("IdState")
|
b.Property<short>("IdState")
|
||||||
.HasColumnType("smallint")
|
.HasColumnType("smallint")
|
||||||
.HasColumnName("state")
|
.HasColumnName("state")
|
||||||
.HasComment("состояние:\n100 - удален");
|
.HasComment("состояние:\n0 - не активен, \n1 - активен, \n2 - заблокирован");
|
||||||
|
|
||||||
b.Property<string>("Login")
|
b.Property<string>("Login")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
@ -4826,6 +4918,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
Id = 1,
|
Id = 1,
|
||||||
Email = "",
|
Email = "",
|
||||||
IdCompany = 1,
|
IdCompany = 1,
|
||||||
|
IdState = (short)1,
|
||||||
Login = "dev",
|
Login = "dev",
|
||||||
Name = "Разработчик",
|
Name = "Разработчик",
|
||||||
PasswordHash = "Vlcj|4fa529103dde7ff72cfe76185f344d4aa87931f8e1b2044e8a7739947c3d18923464eaad93843e4f809c5e126d013072"
|
PasswordHash = "Vlcj|4fa529103dde7ff72cfe76185f344d4aa87931f8e1b2044e8a7739947c3d18923464eaad93843e4f809c5e126d013072"
|
||||||
@ -7559,6 +7652,25 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Navigation("Well");
|
b.Navigation("Well");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Notification", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("AsbCloudDb.Model.NotificationCategory", "NotificationCategory")
|
||||||
|
.WithMany("Notifications")
|
||||||
|
.HasForeignKey("IdNotificationCategory")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("AsbCloudDb.Model.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("IdUser")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("NotificationCategory");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.OperationValue", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.OperationValue", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory")
|
b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory")
|
||||||
@ -8151,6 +8263,11 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Navigation("Measures");
|
b.Navigation("Measures");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.NotificationCategory", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Notifications");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.Permission", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.Permission", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("RelationUserRolePermissions");
|
b.Navigation("RelationUserRolePermissions");
|
||||||
|
@ -74,8 +74,9 @@ namespace AsbCloudDb.Model
|
|||||||
public static int ReferenceCount => referenceCount;
|
public static int ReferenceCount => referenceCount;
|
||||||
|
|
||||||
public DbSet<Faq> Faqs => Set<Faq>();
|
public DbSet<Faq> Faqs => Set<Faq>();
|
||||||
|
|
||||||
public DbSet<HelpPage> HelpPages => Set<HelpPage>();
|
public DbSet<HelpPage> HelpPages => Set<HelpPage>();
|
||||||
|
public DbSet<Notification> Notifications => Set<Notification>();
|
||||||
|
public DbSet<NotificationCategory> NotificationCategories => Set<NotificationCategory>();
|
||||||
|
|
||||||
public AsbCloudDbContext() : base()
|
public AsbCloudDbContext() : base()
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,9 @@ namespace AsbCloudDb.Model
|
|||||||
public string Caption { get; set; } = null!;
|
public string Caption { get; set; } = null!;
|
||||||
public bool IsContact { get; set; }
|
public bool IsContact { get; set; }
|
||||||
|
|
||||||
|
[Column("order")]
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
[InverseProperty(nameof(Company.CompanyType))]
|
[InverseProperty(nameof(Company.CompanyType))]
|
||||||
public virtual ICollection<Company> Companies { get; set; } = null!;
|
public virtual ICollection<Company> Companies { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ namespace AsbCloudDb.Model.DefaultData
|
|||||||
{ typeof(WellType), new EntityFillerWellType()},
|
{ typeof(WellType), new EntityFillerWellType()},
|
||||||
{ typeof(MeasureCategory), new EntityFillerMeasureCategory()},
|
{ typeof(MeasureCategory), new EntityFillerMeasureCategory()},
|
||||||
{ typeof(CompanyType), new EntityFillerCompanyType()},
|
{ typeof(CompanyType), new EntityFillerCompanyType()},
|
||||||
{ typeof(AsbCloudDb.Model.Subsystems.Subsystem), new EntityFillerSubsystem() },
|
{ typeof(Subsystems.Subsystem), new EntityFillerSubsystem() },
|
||||||
|
{ typeof(NotificationCategory), new EntityNotificationCategory()},
|
||||||
};
|
};
|
||||||
return fillers;
|
return fillers;
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
internal class EntityFillerCompanyType : EntityFiller<CompanyType>
|
internal class EntityFillerCompanyType : EntityFiller<CompanyType>
|
||||||
{
|
{
|
||||||
public override CompanyType[] GetData() => new CompanyType[] {
|
public override CompanyType[] GetData() => new CompanyType[] {
|
||||||
new (){ Id = 1, Caption = "Недрапользователь", },
|
new (){ Id = 1, Caption = "Недрапользователь", Order = 1 },
|
||||||
new (){ Id = 2, Caption = "Буровой подрядчик", },
|
new (){ Id = 2, Caption = "Буровой подрядчик", Order = 2 },
|
||||||
new (){ Id = 3, Caption = "Сервис автоматизации бурения", },
|
new (){ Id = 3, Caption = "Сервис автоматизации бурения", Order = 0 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
Login = "dev",
|
Login = "dev",
|
||||||
PasswordHash = "Vlcj|4fa529103dde7ff72cfe76185f344d4aa87931f8e1b2044e8a7739947c3d18923464eaad93843e4f809c5e126d013072",
|
PasswordHash = "Vlcj|4fa529103dde7ff72cfe76185f344d4aa87931f8e1b2044e8a7739947c3d18923464eaad93843e4f809c5e126d013072",
|
||||||
Name = "Разработчик",
|
Name = "Разработчик",
|
||||||
|
IdState = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace AsbCloudDb.Model.DefaultData;
|
||||||
|
|
||||||
|
public class EntityNotificationCategory : EntityFiller<NotificationCategory>
|
||||||
|
{
|
||||||
|
public override NotificationCategory[] GetData() => new NotificationCategory[]
|
||||||
|
{
|
||||||
|
new() { Id = 1, Name = "Системные уведомления" }
|
||||||
|
};
|
||||||
|
}
|
@ -68,7 +68,8 @@ namespace AsbCloudDb.Model
|
|||||||
DbSet<Record60> Record60 { get; }
|
DbSet<Record60> Record60 { get; }
|
||||||
DbSet<Record61> Record61 { get; }
|
DbSet<Record61> Record61 { get; }
|
||||||
DbSet<HelpPage> HelpPages { get; }
|
DbSet<HelpPage> HelpPages { get; }
|
||||||
|
DbSet<Notification> Notifications { get; }
|
||||||
|
DbSet<NotificationCategory> NotificationCategories { get; }
|
||||||
DatabaseFacade Database { get; }
|
DatabaseFacade Database { get; }
|
||||||
|
|
||||||
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
||||||
|
41
AsbCloudDb/Model/Notification.cs
Normal file
41
AsbCloudDb/Model/Notification.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Model;
|
||||||
|
|
||||||
|
[Table("t_notification"), Comment("Уведомления")]
|
||||||
|
public class Notification : IId
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[Column("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("id_user"), Comment("Id получателя")]
|
||||||
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
|
[Column("id_notification_category"), Comment("Id категории уведомления")]
|
||||||
|
public int IdNotificationCategory { get; set; }
|
||||||
|
|
||||||
|
[Column("title"), Comment("Заголовок уведомления")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("message"), Comment("Сообщение уведомления")]
|
||||||
|
public string Message { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("sent_date"), Comment("Дата отправки уведомления")]
|
||||||
|
public DateTime? SentDate { get; set; }
|
||||||
|
|
||||||
|
[Column("read_date"), Comment("Дата прочтения уведомления")]
|
||||||
|
public DateTime? ReadDate { get; set; }
|
||||||
|
|
||||||
|
[Column("id_transport_type"), Comment("Id типа доставки уведомления")]
|
||||||
|
public int IdTransportType { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdNotificationCategory))]
|
||||||
|
public virtual NotificationCategory NotificationCategory { get; set; } = null!;
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdUser))]
|
||||||
|
public virtual User User { get; set; } = null!;
|
||||||
|
}
|
20
AsbCloudDb/Model/NotificationCategory.cs
Normal file
20
AsbCloudDb/Model/NotificationCategory.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Model;
|
||||||
|
|
||||||
|
[Table("t_notification_category"), Comment("Категории уведомлений")]
|
||||||
|
public class NotificationCategory : IId
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[Column("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("name")]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[InverseProperty(nameof(Notification.NotificationCategory))]
|
||||||
|
public virtual ICollection<Notification> Notifications { get; set; } = null!;
|
||||||
|
}
|
@ -8,6 +8,8 @@ namespace AsbCloudDb.Model
|
|||||||
[Table("t_user"), Comment("Пользователи облака")]
|
[Table("t_user"), Comment("Пользователи облака")]
|
||||||
public partial class User : IId
|
public partial class User : IId
|
||||||
{
|
{
|
||||||
|
public const int ActiveStateId = 1;
|
||||||
|
|
||||||
[Key]
|
[Key]
|
||||||
[Column("id")]
|
[Column("id")]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
@ -23,8 +25,8 @@ namespace AsbCloudDb.Model
|
|||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string PasswordHash { get; set; } = null!;
|
public string PasswordHash { get; set; } = null!;
|
||||||
|
|
||||||
[Column("state"), Comment("состояние:\n100 - удален")]
|
[Column("state"), Comment("состояние:\n0 - не активен, \n1 - активен, \n2 - заблокирован")]
|
||||||
public short? IdState { get; set; }
|
public short IdState { get; set; }
|
||||||
|
|
||||||
[Column("name"), Comment("имя")]
|
[Column("name"), Comment("имя")]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
|
@ -23,6 +23,7 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure
|
||||||
{
|
{
|
||||||
@ -82,6 +83,11 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<WellFinalDocumentDto, WellFinalDocument>();
|
.ForType<WellFinalDocumentDto, WellFinalDocument>();
|
||||||
|
|
||||||
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
|
.ForType<NotificationDto, Notification>()
|
||||||
|
.Ignore(dst => dst.NotificationCategory,
|
||||||
|
dst => dst.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
||||||
@ -143,6 +149,11 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
services.AddTransient<IGtrRepository, GtrWitsRepository>();
|
services.AddTransient<IGtrRepository, GtrWitsRepository>();
|
||||||
|
|
||||||
|
services.AddTransient<NotificationService>();
|
||||||
|
services.AddTransient<INotificationRepository, NotificationRepository>();
|
||||||
|
services.AddTransient<ICrudRepository<NotificationCategoryDto>, CrudCacheRepositoryBase<NotificationCategoryDto,
|
||||||
|
NotificationCategory>>();
|
||||||
|
|
||||||
// admin crud services:
|
// admin crud services:
|
||||||
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
||||||
new CrudCacheRepositoryBase<TelemetryDto, Telemetry>(
|
new CrudCacheRepositoryBase<TelemetryDto, Telemetry>(
|
||||||
|
105
AsbCloudInfrastructure/Repository/NotificationRepository.cs
Normal file
105
AsbCloudInfrastructure/Repository/NotificationRepository.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using AsbCloudDb;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Repository;
|
||||||
|
|
||||||
|
public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, Notification>, INotificationRepository
|
||||||
|
{
|
||||||
|
private static IQueryable<Notification> MakeQueryNotification(DbSet<Notification> dbSet)
|
||||||
|
=> dbSet.Include(n => n.NotificationCategory)
|
||||||
|
.AsNoTracking();
|
||||||
|
|
||||||
|
public NotificationRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
||||||
|
: base(dbContext, memoryCache, 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,
|
||||||
|
NotificationRequest request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var skip = request.Skip ?? 0;
|
||||||
|
var take = request.Take ?? 10;
|
||||||
|
|
||||||
|
var query = BuildQuery(idUser, request);
|
||||||
|
|
||||||
|
var result = new PaginationContainer<NotificationDto>()
|
||||||
|
{
|
||||||
|
Skip = skip,
|
||||||
|
Take = take,
|
||||||
|
Count = await query.CountAsync(cancellationToken),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result.Count < skip)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result.Items = await query
|
||||||
|
.SortBy(request.SortFields)
|
||||||
|
.Skip(skip)
|
||||||
|
.Take(take)
|
||||||
|
.AsNoTracking()
|
||||||
|
.Select(x => x.Adapt<NotificationDto>())
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQueryable<Notification> BuildQuery(int idUser,
|
||||||
|
NotificationRequest request)
|
||||||
|
{
|
||||||
|
var query = dbContext.Notifications
|
||||||
|
.Include(x => x.NotificationCategory)
|
||||||
|
.Where(n => n.IdUser == idUser);
|
||||||
|
|
||||||
|
if (request.IsSent.HasValue)
|
||||||
|
{
|
||||||
|
if(request.IsSent.Value)
|
||||||
|
query = query.Where(n => n.SentDate != null);
|
||||||
|
else
|
||||||
|
query = query.Where(n => n.SentDate == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.IdTransportType.HasValue)
|
||||||
|
query = query.Where(n => n.IdTransportType == request.IdTransportType);
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
@ -50,9 +50,12 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<CompanyTypeDto>> GetTypesAsync(CancellationToken token)
|
public async Task<IEnumerable<CompanyTypeDto>> GetTypesAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var query = db.CompaniesTypes.Where(t => t.IsContact);
|
var query = db.CompaniesTypes
|
||||||
|
.Where(t => t.IsContact)
|
||||||
|
.Where(t => t.Companies.Any(c => c.Users.Any() && c.RelationCompaniesWells.Any(w => w.IdWell == idWell)))
|
||||||
|
.OrderBy(t => t.Order);
|
||||||
|
|
||||||
var entities = await query.AsNoTracking()
|
var entities = await query.AsNoTracking()
|
||||||
.ToArrayAsync(token)
|
.ToArrayAsync(token)
|
||||||
|
@ -92,6 +92,6 @@ public class HelpPageController : ControllerBase
|
|||||||
cancellationToken);
|
cancellationToken);
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
return File(memoryStream, "application/octet-stream", file.fileName);
|
return File(memoryStream, "application/pdf", file.fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
148
AsbCloudWebApi/Controllers/NotificationController.cs
Normal file
148
AsbCloudWebApi/Controllers/NotificationController.cs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Уведомления
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/notification")]
|
||||||
|
public class NotificationController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly NotificationService notificationService;
|
||||||
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
|
||||||
|
public NotificationController(NotificationService notificationService,
|
||||||
|
INotificationRepository notificationRepository)
|
||||||
|
{
|
||||||
|
this.notificationService = notificationService;
|
||||||
|
this.notificationRepository = notificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Отправка уведомления
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser">Id пользователя</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>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[Route("send")]
|
||||||
|
public async Task<IActionResult> SendAsync([Required] int idUser,
|
||||||
|
[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,
|
||||||
|
idNotificationCategory,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
idNotificationTransport,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление уведомления
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idNotification">Id уведомления</param>
|
||||||
|
/// <param name="isRead">Прочитано ли уведомление</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPut]
|
||||||
|
[Route("update")]
|
||||||
|
public async Task<IActionResult> UpdateAsync([Required] int idNotification,
|
||||||
|
[Required] bool isRead,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await notificationService.UpdateNotificationAsync(idNotification,
|
||||||
|
isRead,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение уведомления по Id
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idNotification">Id уведомления</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Route("get/{idNotification}")]
|
||||||
|
[ProducesResponseType(typeof(NotificationDto), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public async Task<IActionResult> GetAsync([Required] int idNotification,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken);
|
||||||
|
|
||||||
|
if (notification is null)
|
||||||
|
{
|
||||||
|
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(idNotification),
|
||||||
|
"Уведомление не найдено"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение списка уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Параметры запроса</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Route("getList")]
|
||||||
|
[ProducesResponseType(typeof(PaginationContainer<NotificationDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public async Task<IActionResult> GetListAsync([FromQuery] NotificationRequest request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
int? idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var result = await notificationRepository.GetNotificationsAsync(idUser.Value,
|
||||||
|
request,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление уведомления
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idNotification">Id уведомления</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("delete")]
|
||||||
|
public async Task<IActionResult> DeleteAsync([Required] int idNotification,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await notificationRepository.DeleteAsync(idNotification,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
@ -29,13 +29,14 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// получение списка типов контактов
|
/// получение списка типов контактов
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="idWell">ключ скважины</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet("api/contacts/types")]
|
[HttpGet("api/well/{idWell}/contacts/types")]
|
||||||
[ProducesResponseType(typeof(IEnumerable<CompanyTypeDto>), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<CompanyTypeDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public async Task<IActionResult> GetTypesAsync(CancellationToken token)
|
public async Task<IActionResult> GetTypesAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await wellContactsRepository.GetTypesAsync(token).ConfigureAwait(false);
|
var result = await wellContactsRepository.GetTypesAsync(idWell, token).ConfigureAwait(false);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using AsbCloudApp.Data.GTR;
|
using AsbCloudApp.Data.GTR;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
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;
|
||||||
@ -9,6 +12,9 @@ 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.Services.Notifications;
|
||||||
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
|
using Microsoft.OpenApi.Any;
|
||||||
|
|
||||||
namespace AsbCloudWebApi
|
namespace AsbCloudWebApi
|
||||||
{
|
{
|
||||||
@ -18,8 +24,10 @@ namespace AsbCloudWebApi
|
|||||||
{
|
{
|
||||||
services.AddSwaggerGen(c =>
|
services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
|
c.MapType<TimeSpan>(() => new OpenApiSchema { Type = "string", Example = new OpenApiString("0.00:00:00") });
|
||||||
c.MapType<DateOnly>(() => new OpenApiSchema { Type = "string", Format = "date" });
|
c.MapType<DateOnly>(() => new OpenApiSchema { Type = "string", Format = "date" });
|
||||||
c.MapType<JsonValue>(() => new OpenApiSchema {
|
c.MapType<JsonValue>(() => new OpenApiSchema
|
||||||
|
{
|
||||||
AnyOf = new OpenApiSchema[]
|
AnyOf = new OpenApiSchema[]
|
||||||
{
|
{
|
||||||
new OpenApiSchema {Type = "string", Format = "string" },
|
new OpenApiSchema {Type = "string", Format = "string" },
|
||||||
@ -98,10 +106,39 @@ namespace AsbCloudWebApi
|
|||||||
context.Token = accessToken;
|
context.Token = accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
OnTokenValidated = context =>
|
||||||
|
{
|
||||||
|
var idUser = context.Principal?.GetUserId();
|
||||||
|
if (idUser is null)
|
||||||
|
{
|
||||||
|
context.Fail("idUser is null");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.HttpContext.RequestServices.GetRequiredService<IUserRepository>();
|
||||||
|
var userService = services.BuildServiceProvider().GetRequiredService<IUserRepository>();
|
||||||
|
var user = userService.GetOrDefault(idUser.Value);
|
||||||
|
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
context.Fail("user is null");
|
||||||
|
}
|
||||||
|
else if (user.IdState != User.ActiveStateId)
|
||||||
|
{
|
||||||
|
context.Fail("user is not active");
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddNotificationTransportServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddTransient<INotificationTransportService, SignalRNotificationTransportService>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
AsbCloudWebApi/SignalR/BaseHub.cs
Normal file
19
AsbCloudWebApi/SignalR/BaseHub.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR;
|
||||||
|
|
||||||
|
public abstract class BaseHub : Hub
|
||||||
|
{
|
||||||
|
public virtual Task AddToGroup(string groupName) =>
|
||||||
|
Groups.AddToGroupAsync(Context.ConnectionId, groupName);
|
||||||
|
|
||||||
|
public virtual Task RemoveFromGroup(string groupName) =>
|
||||||
|
Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseHub<T> : BaseHub
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
53
AsbCloudWebApi/SignalR/NotificationHub.cs
Normal file
53
AsbCloudWebApi/SignalR/NotificationHub.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public class NotificationHub : BaseHub
|
||||||
|
{
|
||||||
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
|
private readonly NotificationService notificationService;
|
||||||
|
|
||||||
|
public NotificationHub(ConnectionManagerService connectionManagerService,
|
||||||
|
NotificationService notificationService)
|
||||||
|
{
|
||||||
|
this.connectionManagerService = connectionManagerService;
|
||||||
|
this.notificationService = notificationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnConnectedAsync()
|
||||||
|
{
|
||||||
|
var idUser = Context.User?.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string connectionId = Context.ConnectionId;
|
||||||
|
|
||||||
|
connectionManagerService.AddOrUpdateConnection(idUser.Value, connectionId);
|
||||||
|
|
||||||
|
await base.OnConnectedAsync();
|
||||||
|
|
||||||
|
await notificationService.ResendNotificationAsync(idUser.Value,
|
||||||
|
new NotificationRequest { IsSent = false, IdTransportType = 0},
|
||||||
|
CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnDisconnectedAsync(Exception? exception)
|
||||||
|
{
|
||||||
|
var idUser = Context.User?.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
connectionManagerService.RemoveConnection(idUser.Value);
|
||||||
|
await base.OnDisconnectedAsync(exception);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudWebApi.SignalR
|
namespace AsbCloudWebApi.SignalR
|
||||||
{
|
{
|
||||||
@ -8,12 +6,8 @@ namespace AsbCloudWebApi.SignalR
|
|||||||
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
|
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
|
||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class ReportsHub : Hub<IReportHubClient>
|
public class ReportsHub : BaseHub<IReportHubClient>
|
||||||
{
|
{
|
||||||
public Task AddToGroup(string groupName)
|
|
||||||
=> Groups.AddToGroupAsync(Context.ConnectionId, groupName);
|
|
||||||
|
|
||||||
public Task RemoveFromGroup(string groupName)
|
|
||||||
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
AsbCloudWebApi/SignalR/Services/ConnectionManagerService.cs
Normal file
25
AsbCloudWebApi/SignalR/Services/ConnectionManagerService.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR.Services;
|
||||||
|
|
||||||
|
public class ConnectionManagerService
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<int, string> connections = new();
|
||||||
|
|
||||||
|
public void AddOrUpdateConnection(int userId, string connectionId)
|
||||||
|
{
|
||||||
|
connections.AddOrUpdate(userId, connectionId,
|
||||||
|
(key, existingConnectionId) => connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveConnection(int userId)
|
||||||
|
{
|
||||||
|
connections.TryRemove(userId, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? GetConnectionIdByUserId(int userId)
|
||||||
|
{
|
||||||
|
connections.TryGetValue(userId, out var connectionId);
|
||||||
|
return connectionId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR.Services;
|
||||||
|
|
||||||
|
public class SignalRNotificationTransportService : INotificationTransportService
|
||||||
|
{
|
||||||
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
|
private readonly IHubContext<NotificationHub> notificationHubContext;
|
||||||
|
|
||||||
|
public SignalRNotificationTransportService(ConnectionManagerService connectionManagerService,
|
||||||
|
IHubContext<NotificationHub> notificationHubContext)
|
||||||
|
{
|
||||||
|
this.connectionManagerService = connectionManagerService;
|
||||||
|
this.notificationHubContext = notificationHubContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IdTransportType => 0;
|
||||||
|
|
||||||
|
public async Task SendAsync(NotificationDto notification,
|
||||||
|
CancellationToken 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,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var tasks = notifications
|
||||||
|
.Select(notification => SendAsync(notification, cancellationToken));
|
||||||
|
|
||||||
|
return Task.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudWebApi.SignalR
|
namespace AsbCloudWebApi.SignalR
|
||||||
{
|
{
|
||||||
@ -8,12 +6,8 @@ namespace AsbCloudWebApi.SignalR
|
|||||||
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
|
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
|
||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class TelemetryHub : Hub
|
public class TelemetryHub : BaseHub
|
||||||
{
|
{
|
||||||
public Task AddToGroup(string groupName)
|
|
||||||
=> Groups.AddToGroupAsync(Context.ConnectionId, groupName.ToString());
|
|
||||||
|
|
||||||
public Task RemoveFromGroup(string groupName)
|
|
||||||
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ using AsbCloudInfrastructure;
|
|||||||
using AsbCloudWebApi.Converters;
|
using AsbCloudWebApi.Converters;
|
||||||
using AsbCloudWebApi.Middlewares;
|
using AsbCloudWebApi.Middlewares;
|
||||||
using AsbCloudWebApi.SignalR;
|
using AsbCloudWebApi.SignalR;
|
||||||
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -42,9 +43,12 @@ namespace AsbCloudWebApi
|
|||||||
|
|
||||||
services.AddInfrastructure(Configuration);
|
services.AddInfrastructure(Configuration);
|
||||||
|
|
||||||
|
services.AddNotificationTransportServices();
|
||||||
|
|
||||||
services.AddJWTAuthentication();
|
services.AddJWTAuthentication();
|
||||||
|
|
||||||
services.AddSignalR();
|
services.AddSignalR()
|
||||||
|
.Services.AddSingleton<ConnectionManagerService>();
|
||||||
|
|
||||||
services.AddCors(options =>
|
services.AddCors(options =>
|
||||||
{
|
{
|
||||||
@ -147,6 +151,7 @@ namespace AsbCloudWebApi
|
|||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
|
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://test.digitaldrilling.ru/hubs/telemetry", connectionOptions => {
|
.WithUrl("http://localhost:5000/hubs/notifications", connectionOptions => {
|
||||||
connectionOptions.AccessTokenProvider = AccessTokenProvider;
|
connectionOptions.AccessTokenProvider = AccessTokenProvider;
|
||||||
})
|
})
|
||||||
.WithAutomaticReconnect()
|
.WithAutomaticReconnect()
|
||||||
@ -25,9 +25,10 @@ internal class Program
|
|||||||
Console.WriteLine("connecting");
|
Console.WriteLine("connecting");
|
||||||
connection.StartAsync().Wait();
|
connection.StartAsync().Wait();
|
||||||
|
|
||||||
Console.WriteLine("AddToGroup");
|
//Console.WriteLine("OnConnected");
|
||||||
connection.SendCoreAsync("AddToGroup", new object[] { "well_1" }).Wait();
|
//connection.SendCoreAsync("OnConnected", new object[] { }, CancellationToken.None).Wait();
|
||||||
var subsction = connection.On<object>("UpdateProcessMap", (str1) => {
|
|
||||||
|
var subsction = connection.On<object>("receiveNotifications", (str1) => {
|
||||||
Console.WriteLine(str1);
|
Console.WriteLine(str1);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user