Merge branch 'dev' into feature/ProcessMapReport

This commit is contained in:
ngfrolov 2022-12-28 15:22:50 +05:00
commit fb4bb375e1
32 changed files with 638 additions and 649 deletions

View File

@ -18,7 +18,4 @@
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" /> <EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AsbCloudDb\AsbCloudDb.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -2,6 +2,7 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
#nullable enable
/// <summary> /// <summary>
/// DTO журнала запросов /// DTO журнала запросов
/// </summary> /// </summary>
@ -10,7 +11,7 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// логин пользователя /// логин пользователя
/// </summary> /// </summary>
public string UserLogin { get; set; } public string UserLogin { get; set; } = string.Empty;
/// <summary> /// <summary>
/// Id пользователя /// Id пользователя
@ -20,22 +21,22 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// IP адрес пользователя /// IP адрес пользователя
/// </summary> /// </summary>
public string UserIp { get; set; } public string? UserIp { get; set; }
/// <summary> /// <summary>
/// метод запроса (GET, POST,..) /// метод запроса (GET, POST,..)
/// </summary> /// </summary>
public string RequestMethod { get; set; } public string RequestMethod { get; set; } = null!;
/// <summary> /// <summary>
/// url /// url
/// </summary> /// </summary>
public string RequestPath { get; set; } public string? RequestPath { get; set; }
/// <summary> /// <summary>
/// Referer /// Referer
/// </summary> /// </summary>
public string Referer { get; set; } public string Referer { get; set; } = string.Empty;
/// <summary> /// <summary>
/// продолжительность выполнения /// продолжительность выполнения
@ -47,19 +48,20 @@ namespace AsbCloudApp.Data
/// </summary> /// </summary>
public int Status { get; set; } public int Status { get; set; }
/// <summary>
/// сообщение об ошибке, если она произошла
/// </summary>
public string ExceptionMessage { get; set; }
/// <summary> /// <summary>
/// метка времени запроса /// метка времени запроса
/// </summary> /// </summary>
public DateTime Date { get; set; } public DateTime Date { get; set; }
/// <summary>
/// сообщение об ошибке, если она произошла
/// </summary>
public string? ExceptionMessage { get; set; } = null!;
/// <summary> /// <summary>
/// стек вызовов /// стек вызовов
/// </summary> /// </summary>
public string ExceptionStack { get; set; } public string? ExceptionStack { get; set; } = null!;
} }
#nullable disable
} }

View File

@ -2,6 +2,7 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
#nullable enable
/// <summary> /// <summary>
/// DTO статистики запросов по пользователю /// DTO статистики запросов по пользователю
/// </summary> /// </summary>
@ -15,12 +16,12 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// логин /// логин
/// </summary> /// </summary>
public string Login { get; set; } public string Login { get; set; } = string.Empty;
/// <summary> /// <summary>
/// IP адрес пользователя /// IP адрес пользователя
/// </summary> /// </summary>
public string Ip { get; set; } public string? Ip { get; set; }
/// <summary> /// <summary>
/// время выполнения запроса /// время выполнения запроса
@ -45,6 +46,7 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// DTO пользователя /// DTO пользователя
/// </summary> /// </summary>
public UserDto User { get; set; } public UserDto User { get; set; } = null!;
} }
#nullable disable
} }

View File

@ -1,6 +1,4 @@
using AsbCloudDb.Model; namespace AsbCloudApp.Data.SAUB
namespace AsbCloudApp.Data.SAUB
{ {
/// <summary> /// <summary>
/// Пользователь панели оператора /// Пользователь панели оператора

View File

@ -10,7 +10,7 @@ namespace AsbCloudApp.Data.Subsystems
/// <summary> /// <summary>
/// Активная скважина /// Активная скважина
/// </summary> /// </summary>
public WellDto Well { get; set; } = null!; //TODO: заменить на WellInfo public WellInfoDto Well { get; set; } = null!;
/// <summary> /// <summary>
/// Наработки подсистемы АКБ /// Наработки подсистемы АКБ
/// </summary> /// </summary>

View File

@ -0,0 +1,44 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Repositories
{
#nullable enable
/// <summary>
/// Сервис информации о кустах
/// </summary>
public interface IDepositRepository
{
/// <summary>
/// список месторождений, доступных для пользователя
/// </summary>
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DepositDto>> GetAsync(int idCompany,
CancellationToken token);
/// <summary>
/// Список месторождений/кустов/скважин у которых заполненны параметры бурения
/// </summary>
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DepositDto>> GetAllWithDrillParamsAsync(int idCompany,
CancellationToken token = default);
/// <summary>
/// Список кустов месторождения доступных компании
/// </summary>
/// <param name="idCompany"></param>
/// <param name="depositId"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
int depositId, CancellationToken token);
}
#nullable disable
}

View File

@ -2,6 +2,7 @@
namespace AsbCloudApp.Requests namespace AsbCloudApp.Requests
{ {
#nullable enable
/// <summary> /// <summary>
/// Базовые параметры запроса /// Базовые параметры запроса
/// </summary> /// </summary>
@ -22,6 +23,7 @@ namespace AsbCloudApp.Requests
/// Содержат список названий полей сортировки /// Содержат список названий полей сортировки
/// Указать направление сортировки можно через пробел "asc" или "desc" /// Указать направление сортировки можно через пробел "asc" или "desc"
/// </summary> /// </summary>
public IEnumerable<string> SortFields { get; set; } public IEnumerable<string>? SortFields { get; set; }
} }
#nullable disable
} }

View File

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
namespace AsbCloudApp.Requests
{
#nullable enable
/// <summary>
/// параметры для запроса списка операций
/// </summary>
public class WellOperationRequestBase: RequestBase
{
/// <summary>
/// фильтр по дате начала операции
/// </summary>
public DateTime? GeDate { get; set; }
/// <summary>
/// фильтр по дате окончания операции
/// </summary>
public DateTime? LeDate { get; set; }
/// <summary>
/// фильтр по максимальной глубине скважины
/// </summary>
public double? LeDepth { get; set; }
/// <summary>
/// фильтр по минимальной глубине скважины
/// </summary>
public double? GeDepth { get; set; }
/// <summary>
/// фильтр по списку id категорий операции
/// </summary>
public IEnumerable<int>? OperationCategoryIds { get; set; }
/// <summary>
/// фильтр по план = 0, факт = 1
/// </summary>
public int? OperationType { get; set; }
/// <summary>
/// фильтр по списку id конструкций секции
/// </summary>
public IEnumerable<int>? SectionTypeIds { get; set; }
}
/// <summary>
/// Параметры для запроса списка операций (с id скважины)
/// </summary>
public class WellOperationRequest: WellOperationRequestBase
{
/// <summary>
/// id скважины
/// </summary>
public int IdWell { get; set; }
/// <summary>
/// ctor
/// </summary>
public WellOperationRequest(){}
/// <summary>
/// копирующий конструктор
/// </summary>
/// <param name="request"></param>
/// <param name="idWell"></param>
public WellOperationRequest(WellOperationRequestBase request, int idWell)
{
this.IdWell = idWell;
this.GeDepth = request.GeDepth;
this.LeDepth = request.LeDepth;
this.GeDate = request.GeDate;
this.LeDate = request.LeDate;
this.OperationCategoryIds = request.OperationCategoryIds;
this.OperationType = request.OperationType;
this.SectionTypeIds = request.SectionTypeIds;
this.Skip= request.Skip;
this.Take= request.Take;
this.SortFields = request.SortFields;
}
}
#nullable disable
}

View File

@ -1,62 +0,0 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
//TODO: remove unused methods
/// <summary>
/// Сервис информации о кустах
/// </summary>
public interface IClusterService
{
/// <summary>
/// список месторождений
/// </summary>
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DepositDto>> GetDepositsAsync(int idCompany,
CancellationToken token);
/// <summary>
/// Список кустов с заполненными параметрами бурения
/// </summary>
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DepositDto>> GetDepositsDrillParamsAsync(int idCompany,
CancellationToken token = default);
/// <summary>
/// Список кустов месторождения доступных компании
/// </summary>
/// <param name="idCompany"></param>
/// <param name="depositId"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
int depositId, CancellationToken token);
/// <summary>
/// Список кустов доступных компании
/// </summary>
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
CancellationToken token);
/// <summary>
/// Список скважин доступных компании
/// </summary>
/// <param name="idCompany"></param>
/// <param name="clusterId"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellDto>> GetWellsAsync(int idCompany,
int clusterId, CancellationToken token);
}
}

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
// TODO: make this nullable #nullable enable
/// <summary> /// <summary>
/// Отслеживание и сбор статистики по запросам /// Отслеживание и сбор статистики по запросам
@ -29,34 +29,35 @@ namespace AsbCloudApp.Services
/// </summary> /// </summary>
/// <param name="take"></param> /// <param name="take"></param>
/// <returns></returns> /// <returns></returns>
IEnumerable<RequestLogDto> GetAll(int take = -1); IEnumerable<RequestLogDto> GetAll(int? take);
/// <summary> /// <summary>
/// запросы которые выполнялись быстро /// запросы которые выполнялись быстро
/// </summary> /// </summary>
/// <param name="take"></param> /// <param name="take"></param>
/// <returns></returns> /// <returns></returns>
IEnumerable<RequestLogDto> GetFast(int take = -1); IEnumerable<RequestLogDto> GetFast(int? take);
/// <summary> /// <summary>
/// запросы, которые выполнялись медленно /// запросы, которые выполнялись медленно
/// </summary> /// </summary>
/// <param name="take"></param> /// <param name="take"></param>
/// <returns></returns> /// <returns></returns>
IEnumerable<RequestLogDto> GetSlow(int take = -1); IEnumerable<RequestLogDto> GetSlow(int? take);
/// <summary> /// <summary>
/// запросы, которые завершились ошибкой /// запросы, которые завершились ошибкой
/// </summary> /// </summary>
/// <param name="take"></param> /// <param name="take"></param>
/// <returns></returns> /// <returns></returns>
IEnumerable<RequestLogDto> GetError(int take = -1); IEnumerable<RequestLogDto> GetError(int? take);
/// <summary> /// <summary>
/// Статистика посещений пользователей /// Статистика посещений пользователей
/// </summary> /// </summary>
/// <param name="take"></param> /// <param name="take"></param>
/// <returns></returns> /// <returns></returns>
IEnumerable<RequestLogUserDto> GetUsersStat(int take = -1); IEnumerable<RequestLogUserDto> GetUsersStat(int? take);
} }
#nullable disable
} }

View File

@ -1,4 +1,5 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
@ -6,6 +7,7 @@ using System.Threading.Tasks;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
#nullable enable
/// <summary> /// <summary>
/// сервис операций по скважине /// сервис операций по скважине
/// </summary> /// </summary>
@ -21,54 +23,22 @@ namespace AsbCloudApp.Services
/// <summary> /// <summary>
/// Получить список операций /// Получить список операций
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="request"></param>
/// <param name="operationType"></param>
/// <param name="sectionTypeIds"></param>
/// <param name="operationCategoryIds"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="minDepth"></param>
/// <param name="maxDepth"></param>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetOperationsAsync( Task<PaginationContainer<WellOperationDto>> GetOperationsAsync(
int idWell, WellOperationRequest request,
int? operationType = null, CancellationToken token);
IEnumerable<int> sectionTypeIds = null,
IEnumerable<int> operationCategoryIds = null,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
int skip = 0,
int take = 32,
CancellationToken token = default);
/// <summary> /// <summary>
/// Получить статистику операции по скважине с группировкой по категориям /// Получить статистику операции по скважине с группировкой по категориям
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="request"></param>
/// <param name="operationType"></param>
/// <param name="sectionTypeIds"></param>
/// <param name="operationCategoryIds"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="minDepth"></param>
/// <param name="maxDepth"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync( Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(
int idWell, WellOperationRequest request,
int? operationType = null, CancellationToken token);
IEnumerable<int> sectionTypeIds = null,
IEnumerable<int> operationCategoryIds = null,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
CancellationToken token = default);
/// <summary> /// <summary>
/// Получить операцию по id /// Получить операцию по id
@ -76,29 +46,24 @@ namespace AsbCloudApp.Services
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<WellOperationDto> GetOrDefaultAsync(int id, CancellationToken token); Task<WellOperationDto?> GetOrDefaultAsync(int id, CancellationToken token);
//todo: idWell Не нужен
/// <summary> /// <summary>
/// Добавить несколько операций за один раз /// Добавить несколько операций за один раз
/// </summary> /// </summary>
/// <param name="idWell"></param>
/// <param name="wellOperationDtos"></param> /// <param name="wellOperationDtos"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> InsertRangeAsync(int idWell, Task<int> InsertRangeAsync(
IEnumerable<WellOperationDto> wellOperationDtos, CancellationToken token); IEnumerable<WellOperationDto> wellOperationDtos, CancellationToken token);
//todo: id Не нужны
/// <summary> /// <summary>
/// Обновить существующую операцию /// Обновить существующую операцию
/// </summary> /// </summary>
/// <param name="idWell"></param>
/// <param name="idOperation"></param>
/// <param name="item"></param> /// <param name="item"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> UpdateAsync(int idWell, int idOperation, WellOperationDto item, Task<int> UpdateAsync(WellOperationDto item,
CancellationToken token); CancellationToken token);
/// <summary> /// <summary>
@ -130,4 +95,5 @@ namespace AsbCloudApp.Services
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetOperationsByIdWellAsync(int idWell, CancellationToken token); Task<IEnumerable<WellOperationDto>> GetOperationsByIdWellAsync(int idWell, CancellationToken token);
} }
#nullable disable
} }

View File

@ -60,27 +60,27 @@ namespace AsbCloudDb.Model
public DbSet<WITS.Record60> Record60 => Set<WITS.Record60>(); public DbSet<WITS.Record60> Record60 => Set<WITS.Record60>();
public DbSet<WITS.Record61> Record61 => Set<WITS.Record61>(); public DbSet<WITS.Record61> Record61 => Set<WITS.Record61>();
public static int ReferenceCount { get; private set; } private static int referenceCount;
public static int ReferenceCount => referenceCount;
public AsbCloudDbContext() : base() public AsbCloudDbContext() : base()
{ {
ReferenceCount++; Interlocked.Increment(ref referenceCount);
} }
public AsbCloudDbContext(DbContextOptions<AsbCloudDbContext> options) public AsbCloudDbContext(DbContextOptions<AsbCloudDbContext> options)
: base(options) : base(options)
{ {
ReferenceCount++; Interlocked.Increment(ref referenceCount);
} }
~AsbCloudDbContext() ~AsbCloudDbContext()
{ {
ReferenceCount--; Interlocked.Decrement(ref referenceCount);
} }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
if (!optionsBuilder.IsConfigured) if (!optionsBuilder.IsConfigured)
optionsBuilder.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True" optionsBuilder.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True"
//, builder=>builder.EnableRetryOnFailure(2, System.TimeSpan.FromMinutes(1)) //, builder=>builder.EnableRetryOnFailure(2, System.TimeSpan.FromMinutes(1))

View File

@ -0,0 +1,12 @@
-- Добавить все отсутствующие разрешения группе root.
insert into t_relation_user_role_permission
(select
1 as id_user_role,
id as id_permission
from t_permission
where id not in (
select
t_relation_user_role_permission.id_permission
from t_relation_user_role_permission
where id_user_role = 1)
);

View File

@ -109,7 +109,7 @@ namespace AsbCloudInfrastructure
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration)); services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
services.AddTransient<IAuthService, AuthService>(); services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IClusterService, ClusterService>(); services.AddTransient<IDepositRepository, DepositRepository>();
services.AddTransient<IProcessMapRepository, ProcessMapRepository>(); services.AddTransient<IProcessMapRepository, ProcessMapRepository>();
services.AddTransient<IDrillingProgramService, DrillingProgramService>(); services.AddTransient<IDrillingProgramService, DrillingProgramService>();
services.AddTransient<IEventService, EventService>(); services.AddTransient<IEventService, EventService>();

View File

@ -1,4 +1,5 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
@ -8,20 +9,22 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services namespace AsbCloudInfrastructure.Repository
{ {
public class ClusterService : IClusterService #nullable enable
public class DepositRepository : IDepositRepository
{ {
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly IWellService wellService; private readonly IWellService wellService;
public ClusterService(IAsbCloudDbContext db, IWellService wellService) public DepositRepository(IAsbCloudDbContext db, IWellService wellService)
{ {
this.db = db; this.db = db;
this.wellService = wellService; this.wellService = wellService;
} }
public async Task<IEnumerable<DepositDto>> GetDepositsAsync(int idCompany, /// <inheritdoc/>
public async Task<IEnumerable<DepositDto>> GetAsync(int idCompany,
CancellationToken token = default) CancellationToken token = default)
{ {
var wellEntities = await (from well in db.Wells var wellEntities = await (from well in db.Wells
@ -40,7 +43,8 @@ namespace AsbCloudInfrastructure.Services
return dtos; return dtos;
} }
public async Task<IEnumerable<DepositDto>> GetDepositsDrillParamsAsync(int idCompany, /// <inheritdoc/>
public async Task<IEnumerable<DepositDto>> GetAllWithDrillParamsAsync(int idCompany,
CancellationToken token = default) CancellationToken token = default)
{ {
var wellEntities = await (from well in db.Wells var wellEntities = await (from well in db.Wells
@ -59,21 +63,7 @@ namespace AsbCloudInfrastructure.Services
return dtos; return dtos;
} }
public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany, /// <inheritdoc/>
CancellationToken token = default)
{
var entities = await GetWellsForCompany(idCompany)
.Select(e => e.Cluster)
.Distinct()
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Adapt<IEnumerable<ClusterDto>>();
return dtos;
}
public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany, public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
int depositId, CancellationToken token = default) int depositId, CancellationToken token = default)
{ {
@ -90,48 +80,22 @@ namespace AsbCloudInfrastructure.Services
return dtos; return dtos;
} }
public async Task<IEnumerable<WellDto>> GetWellsAsync(int idCompany,
int idCluster, CancellationToken token = default)
{
var entities = await GetWellsForCompany(idCompany)
.Where(e => e.IdCluster == idCluster)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Select(e => new WellDto
{
Id = e.Id,
Caption = e.Caption,
Latitude = e.Latitude,
Longitude = e.Longitude,
Cluster = e.Cluster.Caption,
Deposit = e.Cluster.Deposit.Caption,
});
return dtos;
}
private static IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> GroupWells(IEnumerable<Well> wellEntities) private static IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> GroupWells(IEnumerable<Well> wellEntities)
{ => wellEntities
return wellEntities
.GroupBy(w => w.Cluster) .GroupBy(w => w.Cluster)
.GroupBy(c => c.Key.Deposit); .GroupBy(c => c.Key.Deposit);
}
private IQueryable<Well> GetWellsForCompany(int idCompany) private IQueryable<Well> GetWellsForCompany(int idCompany)
{ => db.Wells
return db.Wells .Include(w => w.RelationCompaniesWells)
.Include(w => w.RelationCompaniesWells) .ThenInclude(r => r.Company)
.ThenInclude(r => r.Company) .Include(w => w.Cluster)
.Include(w => w.Cluster) .ThenInclude(c => c.Deposit)
.ThenInclude(c => c.Deposit) .Where(w => w.RelationCompaniesWells.Any(c => c.IdCompany == idCompany));
.Where(w => w.RelationCompaniesWells.Any(c => c.IdCompany == idCompany));
}
private IEnumerable<DepositDto> CreateDepositDto(IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> gDepositEntities) private IEnumerable<DepositDto> CreateDepositDto(IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> gDepositEntities)
{ {
return gDepositEntities.Select(gDeposit => new DepositDto var dtos = gDepositEntities.Select(gDeposit => new DepositDto
{ {
Id = gDeposit.Key.Id, Id = gDeposit.Key.Id,
Caption = gDeposit.Key.Caption, Caption = gDeposit.Key.Caption,
@ -154,6 +118,8 @@ namespace AsbCloudInfrastructure.Services
}), }),
}), }),
}); });
return dtos;
} }
} }
#nullable disable
} }

View File

@ -35,27 +35,28 @@ namespace AsbCloudInfrastructure.Repository
this.userRoleRepository = userRoleRepository; this.userRoleRepository = userRoleRepository;
} }
public async Task<int> InsertAsync(UserExtendedDto dto, CancellationToken token = default) public async Task<int> InsertAsync(UserExtendedDto dto, CancellationToken token)
{ {
dto.Id = default; dto.Id = default;
var entity = Convert(dto); var entity = Convert(dto);
await AssertLoginIsBusyAsync(dto.Login, token); await AssertLoginIsBusyAsync(dto.Login, token);
var userRoles = await userRoleRepository.GetByNamesAsync(dto.RoleNames, token).ConfigureAwait(false); var userRoles = await userRoleRepository.GetByNamesAsync(dto.RoleNames, token).ConfigureAwait(false);
var updatedEntity = await dbContext.Users.AddAsync(entity, token).ConfigureAwait(false); var updatedEntity = await dbContext.Users.AddAsync(entity, token).ConfigureAwait(false);
await dbContext.SaveChangesAsync(token);
if (userRoles?.Any() == true) if (userRoles?.Any() == true)
await UpdateRolesCacheForUserAsync(updatedEntity.Entity.Id, userRoles, token); await UpdateRolesCacheForUserAsync(updatedEntity.Entity.Id, userRoles, token);
await dbContext.SaveChangesAsync(token);
DropCacheUsers(); DropCacheUsers();
return updatedEntity.Entity.Id; return updatedEntity.Entity.Id;
} }
public Task<int> InsertRangeAsync(IEnumerable<UserExtendedDto> newItems, CancellationToken token = default) public Task<int> InsertRangeAsync(IEnumerable<UserExtendedDto> newItems, CancellationToken token)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public async Task<IEnumerable<UserExtendedDto>> GetAllAsync(CancellationToken token = default) public async Task<IEnumerable<UserExtendedDto>> GetAllAsync(CancellationToken token)
{ {
var dtos = (await GetCacheUserAsync(token)).ToList(); var dtos = (await GetCacheUserAsync(token)).ToList();
if (dtos is null) if (dtos is null)
@ -76,7 +77,7 @@ namespace AsbCloudInfrastructure.Repository
return dto; return dto;
} }
public async Task<UserExtendedDto?> GetOrDefaultAsync(int id, CancellationToken token = default) public async Task<UserExtendedDto?> GetOrDefaultAsync(int id, CancellationToken token)
{ {
var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id); var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
if (dto is null) if (dto is null)
@ -86,7 +87,7 @@ namespace AsbCloudInfrastructure.Repository
return dto; return dto;
} }
public async Task<int> UpdateAsync(UserExtendedDto dto, CancellationToken token = default) public async Task<int> UpdateAsync(UserExtendedDto dto, CancellationToken token)
{ {
if (dto.Id <= 1) if (dto.Id <= 1)
throw new ArgumentInvalidException($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto)); throw new ArgumentInvalidException($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
@ -109,7 +110,7 @@ namespace AsbCloudInfrastructure.Repository
return result.Entity.Id; return result.Entity.Id;
} }
public async Task<int> DeleteAsync(int id, CancellationToken token = default) public async Task<int> DeleteAsync(int id, CancellationToken token)
{ {
var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id); var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
if (dto is null) if (dto is null)
@ -159,7 +160,7 @@ namespace AsbCloudInfrastructure.Repository
.Select(r => r.Caption) .Select(r => r.Caption)
.Distinct(); .Distinct();
private async Task AssertLoginIsBusyAsync(string login, CancellationToken token = default) private async Task AssertLoginIsBusyAsync(string login, CancellationToken token)
{ {
var existingUserDto = (await GetCacheUserAsync(token)) var existingUserDto = (await GetCacheUserAsync(token))
.FirstOrDefault(u => u.Login.ToLower() == login.ToLower()); .FirstOrDefault(u => u.Login.ToLower() == login.ToLower());

View File

@ -98,19 +98,33 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end); protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end);
public static InterpolationLine MakeInterpolationLine( /// <summary>
/// Среднее арифметическое
/// </summary>
/// <param name="yGetter"></param>
/// <param name="telemetry"></param>
/// <param name="begin"></param>
/// <param name="fragmentLength"></param>
/// <returns></returns>
public static double CalcAvgAppr(
Func<DetectableTelemetry, double> yGetter, Func<DetectableTelemetry, double> yGetter,
DetectableTelemetry[] telemetry, DetectableTelemetry[] telemetry,
int begin, int begin,
int fragmentLength) int fragmentLength)
{ {
DetectableTelemetry[] data; var end = begin + fragmentLength;
if (fragmentLength > 0 && (begin + fragmentLength) < telemetry.Length) end = end < telemetry.Length
data = telemetry[begin..(begin + fragmentLength)]; ? end
else : telemetry.Length;
data = telemetry[begin..]; var subData = telemetry[begin..end].Select(yGetter);
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours))); if (end - begin > 10)
return line; {
var ratio = (end - begin) / 5;
subData = subData.Where((_,i) => i % ratio > 0);
}
var avg = subData.Average();
return avg;
} }
/// <summary> /// <summary>

View File

@ -1,4 +1,5 @@
using AsbCloudDb.Model; using AsbCloudDb.Model;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{ {
@ -38,9 +39,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
if (point0.Pressure < 25) if (point0.Pressure < 25)
return IdReasonOfEnd_PressureIsLo; return IdReasonOfEnd_PressureIsLo;
var lineRotorSpeed = MakeInterpolationLine(d => d.RotorSpeed, telemetry, position, 60); var avgRotorSpeed = CalcAvgAppr(d => d.RotorSpeed, telemetry, position, 60);
if (lineRotorSpeed.IsAverageYLessThan(10)) if (avgRotorSpeed < 10)
return IdReasonOfEnd_AvgRotorSpeedIsLo; return IdReasonOfEnd_AvgRotorSpeedIsLo;
if (!DeviatesFromBegin(telemetry, t => t.WellDepth, position, 150, 0.003)) if (!DeviatesFromBegin(telemetry, t => t.WellDepth, position, 150, 0.003))

View File

@ -38,9 +38,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
if (point0.Pressure < 25) if (point0.Pressure < 25)
return IdReasonOfEnd_PressureIsLo; return IdReasonOfEnd_PressureIsLo;
var lineRotorSpeed = MakeInterpolationLine(d => d.RotorSpeed, telemetry, position, 60); var avgRotorSpeed = CalcAvgAppr(d => d.RotorSpeed, telemetry, position, 60);
if (lineRotorSpeed.IsAverageYGreaterThan(10)) if (avgRotorSpeed > 10)
return IdReasonOfEnd_AvgRotorSpeedIsHi; return IdReasonOfEnd_AvgRotorSpeedIsHi;
if (!DeviatesFromBegin(telemetry, t => t.WellDepth, position, 150, 0.003)) if (!DeviatesFromBegin(telemetry, t => t.WellDepth, position, 150, 0.003))

View File

@ -17,6 +17,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
{ {
private const string workId = "Operation detection"; private const string workId = "Operation detection";
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30); private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
private static string progress = "no progress";
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[] private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
{ {
@ -34,7 +35,13 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
public static WorkPeriodic MakeWork() public static WorkPeriodic MakeWork()
{ {
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod); var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod);
workPeriodic.Timeout = TimeSpan.FromMinutes(30); workPeriodic.Timeout = TimeSpan.FromSeconds(15 * 60);
workPeriodic.OnErrorAsync = (id, exception, token) =>
{
var text = $"work {id}, when {progress}, throw error:{exception.Message}";
Trace.TraceWarning(text);
return Task.CompletedTask;
};
return workPeriodic; return workPeriodic;
} }
@ -86,6 +93,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
var query = db.TelemetryDataSaub var query = db.TelemetryDataSaub
.AsNoTracking() .AsNoTracking()
.Where(d => d.IdTelemetry == idTelemetry) .Where(d => d.IdTelemetry == idTelemetry)
.Where(d => d.BlockPosition >= 0)
.Select(d => new DetectableTelemetry .Select(d => new DetectableTelemetry
{ {
DateTime = d.DateTime, DateTime = d.DateTime,
@ -120,20 +128,26 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
var isDetected = false; var isDetected = false;
var positionBegin = 0; var positionBegin = 0;
var positionEnd = data.Length - gap; var positionEnd = data.Length - gap;
var step = 10;
while (positionEnd > positionBegin) while (positionEnd > positionBegin)
{ {
step ++;
for (int i = 0; i < detectors.Length; i++) for (int i = 0; i < detectors.Length; i++)
{ {
progress = $"telemetry:{idTelemetry}, date:{startDate}, pos:{positionBegin}, detector:{detectors[i]}";
if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult? result)) if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult? result))
{ {
detectedOperations.Add(result!.Operation); detectedOperations.Add(result!.Operation);
lastDetectedOperation = result.Operation; lastDetectedOperation = result.Operation;
isDetected = true; isDetected = true;
step = 1;
positionBegin = result.TelemetryEnd; positionBegin = result.TelemetryEnd;
break; break;
} }
} }
positionBegin++; if (step > 20)
step = 10;
positionBegin += step;
} }
if (isDetected) if (isDetected)

View File

@ -7,6 +7,7 @@ using System.Linq;
namespace AsbCloudInfrastructure.Services namespace AsbCloudInfrastructure.Services
{ {
#nullable enable
public class RequestTrackerService : IRequerstTrackerService public class RequestTrackerService : IRequerstTrackerService
{ {
const int fastRequestsCount = 1000; const int fastRequestsCount = 1000;
@ -16,28 +17,28 @@ namespace AsbCloudInfrastructure.Services
const int fastLimitMs = 500; const int fastLimitMs = 500;
static readonly char[] stackTraceSeparators = "\r\n".ToCharArray(); static readonly char[] stackTraceSeparators = "\r\n".ToCharArray();
private readonly ConcurrentQueue<RequestLogDto> fastRequests = new ConcurrentQueue<RequestLogDto>(); private readonly ConcurrentQueue<RequestLogDto> fastRequests = new ();
private readonly ConcurrentQueue<RequestLogDto> slowRequests = new ConcurrentQueue<RequestLogDto>(); private readonly ConcurrentQueue<RequestLogDto> slowRequests = new ();
private readonly ConcurrentQueue<RequestLogDto> errorRequests = new ConcurrentQueue<RequestLogDto>(); private readonly ConcurrentQueue<RequestLogDto> errorRequests = new ();
private readonly ConcurrentDictionary<string, RequestLogUserDto> users = new ConcurrentDictionary<string, RequestLogUserDto>(); private readonly ConcurrentDictionary<string, RequestLogUserDto> users = new ConcurrentDictionary<string, RequestLogUserDto>();
private static IEnumerable<RequestLogDto> Get(IEnumerable<RequestLogDto> list, int take = -1) private static IEnumerable<RequestLogDto> Get(IEnumerable<RequestLogDto> list, int? take)
{ {
IEnumerable<RequestLogDto> orderedlist = list.OrderByDescending(r => r.Date); IEnumerable<RequestLogDto> orderedlist = list.OrderByDescending(r => r.Date);
if (take > 0) if (take > 0)
orderedlist = orderedlist.Take(take); orderedlist = orderedlist.Take(take.Value);
return orderedlist; return orderedlist;
} }
public IEnumerable<RequestLogUserDto> GetUsersStat(int take = -1) public IEnumerable<RequestLogUserDto> GetUsersStat(int? take)
{ {
IEnumerable<RequestLogUserDto> result = users.Values.OrderByDescending(u => u.LastDate); IEnumerable<RequestLogUserDto> result = users.Values.OrderByDescending(u => u.LastDate);
if (take > 0) if (take > 0)
result = result.Take(take); result = result.Take(take.Value);
return result; return result;
} }
public IEnumerable<RequestLogDto> GetAll(int take = -1) public IEnumerable<RequestLogDto> GetAll(int? take)
{ {
var result = fastRequests var result = fastRequests
.Union(slowRequests) .Union(slowRequests)
@ -46,13 +47,13 @@ namespace AsbCloudInfrastructure.Services
return Get(result, take); return Get(result, take);
} }
public IEnumerable<RequestLogDto> GetFast(int take = -1) public IEnumerable<RequestLogDto> GetFast(int? take)
=> Get(fastRequests, take); => Get(fastRequests, take);
public IEnumerable<RequestLogDto> GetSlow(int take = -1) public IEnumerable<RequestLogDto> GetSlow(int? take)
=> Get(slowRequests, take); => Get(slowRequests, take);
public IEnumerable<RequestLogDto> GetError(int take = -1) public IEnumerable<RequestLogDto> GetError(int? take)
=> Get(errorRequests, take); => Get(errorRequests, take);
public void RegisterRequest(RequestLogDto requestLog) public void RegisterRequest(RequestLogDto requestLog)
@ -103,14 +104,13 @@ namespace AsbCloudInfrastructure.Services
{ {
if (!string.IsNullOrEmpty(requestLog.UserLogin)) if (!string.IsNullOrEmpty(requestLog.UserLogin))
{ {
var key = $"{requestLog?.UserId}>{requestLog?.UserIp}"; var key = $"{requestLog.UserId}>{requestLog.UserIp}";
if (!users.ContainsKey(key)) if (!users.ContainsKey(key))
users[key] = new RequestLogUserDto users[key] = new RequestLogUserDto
{ {
UserId = requestLog.UserId, UserId = requestLog.UserId,
Ip = requestLog.UserIp, Ip = requestLog.UserIp,
Login = requestLog.UserLogin, Login = requestLog.UserLogin,
//User = userService.Get(requestLog.UserId),
}; };
users[key].ElapsedMs += requestLog.ElapsedMilliseconds; users[key].ElapsedMs += requestLog.ElapsedMilliseconds;
users[key].LastDate = requestLog.Date; users[key].LastDate = requestLog.Date;
@ -128,4 +128,5 @@ namespace AsbCloudInfrastructure.Services
} }
} }
} }
#nullable disable
} }

View File

@ -38,6 +38,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
using var db = MakeContext(configuration); using var db = MakeContext(configuration);
instance.InitializeCacheFromDB<TEntity>(db); instance.InitializeCacheFromDB<TEntity>(db);
db.Dispose();
}); });
} }
return instance; return instance;

View File

@ -0,0 +1,242 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using System.Collections;
namespace AsbCloudInfrastructure.Services.WellOperationService
{
#nullable enable
/*
var opsQuery = db.WellOperations
.Where( o => o.IdWell == idWell )
.Where( o => o.IdType == idType )
.Select( o => new {
o.Id,
o.IdType,
o.IdWell,
o.IdWellSectionType,
o.IdCategory,
o.Well,
o.WellSectionType,
o.OperationCategory,
o.DateStart,
o.DepthStart,
o.DepthEnd,
o.DurationHours,
o.CategoryInfo,
o.Comment,
nptHours = db.WellOperations
.Where(subOp => subOp.IdWell == idWell)
.Where(subOp => subOp.IdType == idType)
.Where(subOp => nptCats.Contains( subOp.IdCategory ))
.Where(subOp => subOp.DateStart <= o.DateStart)
.Select(subOp => subOp.DurationHours)
.Sum(),
Day = o.DateStart - db.WellOperations
.Where(subOp => subOp.IdWell == idWell)
.Where(subOp => subOp.IdType == idType)
.Where(subOp => subOp.DateStart <= o.DateStart)
.Min(subOp => subOp.DateStart),
})
.OrderBy(o => o.DateStart);
*/
public class WellOperationRepository
{
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
private readonly IWellService wellService;
private static Dictionary<int, DateTimeOffset?>? firstOperationsCache = null;
public const int idOperationTypePlan = 0;
public const int idOperationTypeFact = 1;
public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
{
this.db = db;
this.memoryCache = memoryCache;
this.wellService = wellService;
}
public IDictionary<int, string> GetSectionTypes()
=> memoryCache
.GetOrCreateBasic<WellSectionType>(db)
.ToDictionary(s => s.Id, s => s.Caption);
public IEnumerable<WellOperationCategoryDto> GetCategories()
{
var allCategories = memoryCache
.GetOrCreateBasic<WellOperationCategory>(db);
var parentIds = allCategories
.Select(o => o.IdParent)
.Distinct();
var operationCategories = allCategories
.Where(o => !parentIds.Contains(o.Id))
.OrderBy(o => o.IdParent)
.ThenBy(o => o.Name);
var result = operationCategories.Adapt<IEnumerable<WellOperationCategoryDto>>();
return result;
}
public DateTimeOffset? FirstOperationDate(int idWell)
{
if (firstOperationsCache is null)
{
var query = db.WellOperations
.GroupBy(o => o.IdWell)
.Select(g => new Tuple<int, DateTimeOffset?, DateTimeOffset?>
(
g.Key,
g.Where(o => o.IdType == idOperationTypePlan).Min(o => o.DateStart),
g.Where(o => o.IdType == idOperationTypeFact).Min(o => o.DateStart)
));
firstOperationsCache = query
.ToDictionary(f => f.Item1, f => f.Item3 ?? f.Item2);
}
return firstOperationsCache?.GetValueOrDefault(idWell);
}
public async Task<WellOperationDto?> GetOrDefaultAsync(int id,
CancellationToken token)
{
var entity = await db.WellOperations
.Include(s => s.WellSectionType)
.Include(s => s.OperationCategory)
.FirstOrDefaultAsync(e => e.Id == id, token)
.ConfigureAwait(false);
if (entity is null)
return null;
var timezone = wellService.GetTimezone(entity.IdWell);
var dto = entity.Adapt<WellOperationDto>();
dto.WellSectionTypeName = entity.WellSectionType.Caption;
dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours);
dto.CategoryName = entity.OperationCategory.Name;
return dto;
}
public Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request,
CancellationToken token)
{
return Task.FromResult(Enumerable.Empty<WellOperationDto>());
}
public async Task<int> InsertRangeAsync(
IEnumerable<WellOperationDto> wellOperationDtos,
CancellationToken token)
{
var firstOperation = wellOperationDtos
.FirstOrDefault();
if (firstOperation is null)
return 0;
var idWell = firstOperation.IdWell;
var timezone = wellService.GetTimezone(idWell);
foreach (var dto in wellOperationDtos)
{
var entity = dto.Adapt<WellOperation>();
entity.Id = default;
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
entity.IdWell = idWell;
db.WellOperations.Add(entity);
}
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
public async Task<int> UpdateAsync(
WellOperationDto dto, CancellationToken token)
{
var timezone = wellService.GetTimezone(dto.IdWell);
var entity = dto.Adapt<WellOperation>();
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
db.WellOperations.Update(entity);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
public async Task<int> DeleteAsync(IEnumerable<int> ids,
CancellationToken token)
{
var query = db.WellOperations.Where(e => ids.Contains(e.Id));
db.WellOperations.RemoveRange(query);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
{
var timezone = wellService.GetTimezone(request.IdWell);
var query = db.WellOperations
.Include(s => s.WellSectionType)
.Include(s => s.OperationCategory)
.Where(s => s.IdWell == request.IdWell);
if (request.OperationType.HasValue)
query = query.Where(e => e.IdType == request.OperationType.Value);
if (request.SectionTypeIds?.Any() == true)
query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (request.OperationCategoryIds?.Any() == true)
query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (request.GeDepth.HasValue)
query = query.Where(e => e.DepthEnd >= request.GeDepth.Value);
if (request.LeDepth.HasValue)
query = query.Where(e => e.DepthEnd <= request.LeDepth.Value);
if (request.GeDate.HasValue)
{
var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(e => e.DateStart >= geDateOffset);
}
if (request.LeDate.HasValue)
{
var leDateOffset = request.LeDate.Value.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(e => e.DateStart <= leDateOffset);
}
if (request.SortFields?.Any() == true)
{
query = query.SortBy(request.SortFields);
}
else
{
query = query
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
}
return query;
}
}
#nullable disable
}

View File

@ -1,5 +1,7 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -75,51 +77,32 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
} }
public async Task<PaginationContainer<WellOperationDto>> GetOperationsAsync( public async Task<PaginationContainer<WellOperationDto>> GetOperationsAsync(
int idWell, WellOperationRequest request,
int? operationType = default, CancellationToken token)
IEnumerable<int>? sectionTypeIds = null,
IEnumerable<int>? operationCategoryIds = null,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
int skip = 0,
int take = 32,
CancellationToken token = default)
{ {
var timezone = wellService.GetTimezone(idWell); var timezone = wellService.GetTimezone(request.IdWell);
var query = BuildQuery( var query = BuildQuery(request);
idWell,
operationType,
sectionTypeIds,
operationCategoryIds,
begin,
end,
minDepth,
maxDepth,
token);
var result = new PaginationContainer<WellOperationDto> var result = new PaginationContainer<WellOperationDto>
{ {
Skip = skip, Skip = request.Skip ?? 0,
Take = take, Take = request.Take ?? 32,
Count = await query.CountAsync(token).ConfigureAwait(false), Count = await query.CountAsync(token).ConfigureAwait(false),
}; };
var dateStart = query.Min(o => o.DateStart);
query = query
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
if (skip > 0) if (result.Skip > 0)
query = query.Skip(skip); query = query.Skip(result.Skip!);
var entities = await query.Take(take).AsNoTracking() var entities = await query.Take(result.Take).AsNoTracking()
.ToListAsync(token).ConfigureAwait(false); .ToListAsync(token).ConfigureAwait(false);
if (!entities.Any())
return result;
var nptHours = 0d; var nptHours = 0d;
var dateStart = query.Min(o => o.DateStart);
foreach (var entity in entities) foreach (var entity in entities)
{ {
var dto = entity.Adapt<WellOperationDto>(); var dto = entity.Adapt<WellOperationDto>();
@ -177,26 +160,10 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
} }
public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync( public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(
int idWell, WellOperationRequest request,
int? operationType = default, CancellationToken token)
IEnumerable<int>? sectionTypeIds = default,
IEnumerable<int>? operationCategoryIds = default,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
CancellationToken token = default)
{ {
var query = BuildQuery( var query = BuildQuery(request);
idWell,
operationType,
sectionTypeIds,
operationCategoryIds,
begin,
end,
minDepth,
maxDepth,
token);
var entities = await query var entities = await query
.Select(o => new { .Select(o => new {
o.IdCategory, o.IdCategory,
@ -205,11 +172,12 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
}) })
.ToListAsync(token); .ToListAsync(token);
var parentRelationDictionary = GetCategories() var parentRelationDictionary = GetCategories()
.ToDictionary(c => c.Id, cc => new .ToDictionary(c => c.Id, c => new
{ {
Name = cc.Name, c.Name,
IdParent = cc.IdParent c.IdParent
}); });
var dtos = entities var dtos = entities
.GroupBy(o => o.IdCategory) .GroupBy(o => o.IdCategory)
.Select(g => new WellGroupOpertionDto .Select(g => new WellGroupOpertionDto
@ -239,16 +207,14 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
TotalMinutes = g.Sum(o => o.TotalMinutes), TotalMinutes = g.Sum(o => o.TotalMinutes),
Items = g.ToList(), Items = g.ToList(),
IdParent = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].IdParent : defaultId, IdParent = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].IdParent : defaultId,
}); });
} }
return dtos; return dtos;
} }
public async Task<WellOperationDto?> GetOrDefaultAsync(int id, public async Task<WellOperationDto?> GetOrDefaultAsync(int id,
CancellationToken token = default) CancellationToken token)
{ {
var entity = await db.WellOperations var entity = await db.WellOperations
.Include(s => s.WellSectionType) .Include(s => s.WellSectionType)
.Include(s => s.OperationCategory) .Include(s => s.OperationCategory)
@ -267,10 +233,17 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
return dto; return dto;
} }
public async Task<int> InsertRangeAsync(int idWell, public async Task<int> InsertRangeAsync(
IEnumerable<WellOperationDto> wellOperationDtos, IEnumerable<WellOperationDto> wellOperationDtos,
CancellationToken token = default) CancellationToken token)
{ {
var firstOperation = wellOperationDtos
.FirstOrDefault();
if (firstOperation is null)
return 0;
var idWell = firstOperation.IdWell;
var timezone = wellService.GetTimezone(idWell); var timezone = wellService.GetTimezone(idWell);
foreach (var dto in wellOperationDtos) foreach (var dto in wellOperationDtos)
{ {
@ -285,12 +258,11 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
.ConfigureAwait(false); .ConfigureAwait(false);
} }
public async Task<int> UpdateAsync(int idWell, int idOperation, public async Task<int> UpdateAsync(
WellOperationDto dto, CancellationToken token = default) WellOperationDto dto, CancellationToken token)
{ {
var timezone = wellService.GetTimezone(idWell); var timezone = wellService.GetTimezone(dto.IdWell);
var entity = dto.Adapt<WellOperation>(); var entity = dto.Adapt<WellOperation>();
entity.Id = idOperation;
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours); entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
db.WellOperations.Update(entity); db.WellOperations.Update(entity);
return await db.SaveChangesAsync(token) return await db.SaveChangesAsync(token)
@ -298,7 +270,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
} }
public async Task<int> DeleteAsync(IEnumerable<int> ids, public async Task<int> DeleteAsync(IEnumerable<int> ids,
CancellationToken token = default) CancellationToken token)
{ {
var query = db.WellOperations.Where(e => ids.Contains(e.Id)); var query = db.WellOperations.Where(e => ids.Contains(e.Id));
db.WellOperations.RemoveRange(query); db.WellOperations.RemoveRange(query);
@ -306,59 +278,55 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
.ConfigureAwait(false); .ConfigureAwait(false);
} }
private IQueryable<WellOperation> BuildQuery( private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
int idWell,
int? operationType = default,
IEnumerable<int>? sectionTypeIds = null,
IEnumerable<int>? operationCategoryIds = null,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
CancellationToken token = default)
{ {
var timezone = wellService.GetTimezone(idWell); var timezone = wellService.GetTimezone(request.IdWell);
var query = db.WellOperations var query = db.WellOperations
.Include(s => s.WellSectionType) .Include(s => s.WellSectionType)
.Include(s => s.OperationCategory) .Include(s => s.OperationCategory)
.Where(s => s.IdWell == idWell); .Where(s => s.IdWell == request.IdWell);
var dateStart = query.Min(o => o.DateStart); if (request.OperationType.HasValue)
query = query.Where(e => e.IdType == request.OperationType.Value);
if (operationType.HasValue) if (request.SectionTypeIds?.Any() == true)
query = query.Where(e => e.IdType == operationType.Value); query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (sectionTypeIds != default && sectionTypeIds.Any()) if (request.OperationCategoryIds?.Any() == true)
query = query.Where(e => sectionTypeIds.Contains(e.IdWellSectionType)); query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (operationCategoryIds != default && operationCategoryIds.Any()) if (request.GeDepth.HasValue)
query = query.Where(e => operationCategoryIds.Contains(e.IdCategory)); query = query.Where(e => e.DepthEnd >= request.GeDepth.Value);
if (minDepth != double.MinValue) if (request.LeDepth.HasValue)
query = query.Where(e => e.DepthEnd >= minDepth); query = query.Where(e => e.DepthEnd <= request.LeDepth.Value);
if (maxDepth != double.MaxValue) if (request.GeDate.HasValue)
query = query.Where(e => e.DepthEnd <= maxDepth);
if (begin != default)
{ {
var beginOffset = begin.ToUtcDateTimeOffset(timezone.Hours); var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(e => e.DateStart >= beginOffset); query = query.Where(e => e.DateStart >= geDateOffset);
} }
if (end != default) if (request.LeDate.HasValue)
{ {
var endOffset = end.ToUtcDateTimeOffset(timezone.Hours); var leDateOffset = request.LeDate.Value.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(e => e.DateStart <= endOffset); query = query.Where(e => e.DateStart <= leDateOffset);
}
if (request.SortFields?.Any() == true)
{
query = query.SortBy(request.SortFields);
}
else
{
query = query
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
} }
query = query
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
return query; return query;
} }
} }
#nullable disable #nullable disable

View File

@ -1,170 +0,0 @@
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services;
using Moq;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace AsbCloudWebApi.Tests.ServicesTests;
public class ClusterServiceTest
{
private readonly AsbCloudDbContext context;
private readonly Mock<IWellService> wellService;
private readonly List<Deposit> deposits = new()
{
new Deposit { Id = 1, Caption = "Test deposit 1" },
new Deposit { Id = 2, Caption = "Test deposit 2" },
new Deposit { Id = 3, Caption = "Test deposit 3" },
new Deposit { Id = 4, Caption = "Test deposit 4" }
};
private readonly List<Cluster> clusters = new()
{
new Cluster { Id = 1, Caption = "Test cluster 1", IdDeposit = 1, Timezone = new SimpleTimezone()},
new Cluster { Id = 2, Caption = "Test cluster 2", IdDeposit = 1, Timezone = new SimpleTimezone() },
new Cluster { Id = 3, Caption = "Test cluster 3", IdDeposit = 2, Timezone = new SimpleTimezone() },
new Cluster { Id = 4, Caption = "Test cluster 4", IdDeposit = 2, Timezone = new SimpleTimezone() }
};
private readonly List<Well> wells = new()
{
new Well { Id = 1, Caption = "Test well 1", IdCluster = 1 },
new Well { Id = 2, Caption = "Test well 2", IdCluster = 2 },
new Well { Id = 3, Caption = "Test well 3", IdCluster = 1 },
new Well { Id = 4, Caption = "Test well 4", IdCluster = 2 }
};
private readonly List<CompanyType> companiesTypes = new()
{
new CompanyType { Id = 1, Caption = "test company type"}
};
private readonly List<Company> companies = new()
{
new Company { Id = 1, Caption = "Test company 1", IdCompanyType = 1},
new Company { Id = 2, Caption = "Test company 2", IdCompanyType = 1}
};
private readonly List<RelationCompanyWell> relations = new()
{
new RelationCompanyWell { IdCompany = 1, IdWell = 1 },
new RelationCompanyWell { IdCompany = 1, IdWell = 2 },
new RelationCompanyWell { IdCompany = 2, IdWell = 2 }
};
private readonly List<WellSectionType> wellSectionTypes = new()
{
new WellSectionType { Id = 1, Caption = "Test well section type 1" }
};
public ClusterServiceTest()
{
context = TestHelpter.MakeRealTestContext();
wellService = new Mock<IWellService>();
context.Deposits.RemoveRange(context.Deposits);
context.Clusters.RemoveRange(context.Clusters);
context.Wells.RemoveRange(context.Wells);
context.CompaniesTypes.RemoveRange(context.CompaniesTypes);
context.Companies.RemoveRange(context.Companies);
context.RelationCompaniesWells.RemoveRange(context.RelationCompaniesWells);
context.WellSectionTypes.RemoveRange(context.WellSectionTypes);
if (context.ChangeTracker.HasChanges())
context.SaveChanges();
context.Deposits.AddRange(deposits);
context.Clusters.AddRange(clusters);
context.Wells.AddRange(wells);
context.CompaniesTypes.AddRange(companiesTypes);
context.Companies.AddRange(companies);
context.RelationCompaniesWells.AddRange(relations);
context.WellSectionTypes.AddRange(wellSectionTypes);
context.SaveChanges();
}
~ClusterServiceTest()
{
context.Deposits.RemoveRange(context.Deposits);
context.Clusters.RemoveRange(context.Clusters);
context.Wells.RemoveRange(context.Wells);
context.CompaniesTypes.RemoveRange(context.CompaniesTypes);
context.Companies.RemoveRange(context.Companies);
context.RelationCompaniesWells.RemoveRange(context.RelationCompaniesWells);
context.SaveChanges();
}
[Fact]
public async Task GetDepositsAsync_returns_one_deposit()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetDepositsAsync(1);
Assert.Single(dtos);
}
[Fact]
public async Task GetDepositsAsync_returns_one_deposit_with_two_clusters()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetDepositsAsync(1);
Assert.Equal(2, dtos.FirstOrDefault()?.Clusters.Count());
}
[Fact]
public async Task GetDrillParamsAsync_returns_depositDtos()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetDepositsDrillParamsAsync(1);
Assert.True(dtos.Any());
}
[Fact]
public async Task GetDrillParamsAsync_returns_one_deposit()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetDepositsDrillParamsAsync(1);
Assert.Single(dtos);
}
[Fact]
public async Task GetDrillParamsAsync_returns_one_deposit_with_two_clusters()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetDepositsDrillParamsAsync(1);
Assert.Equal(2, dtos.FirstOrDefault()?.Clusters.Count());
}
[Fact]
public async Task GetClustersAsync_returns_two_dtos()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetClustersAsync(1);
Assert.Equal(2, dtos.Count());
}
[Fact]
public async Task GetClustersAsync_with_deposit_returns_two_clusters()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetClustersAsync(1, 1);
Assert.Equal(2, dtos.Count());
}
[Fact]
public async Task GetWellsAsync_returns_one_well_by_cluster_and_company()
{
var service = new ClusterService(context, wellService.Object);
var dtos = await service.GetWellsAsync(1, 1);
Assert.Single(dtos);
}
}

View File

@ -1,67 +0,0 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers
{
/// <summary>
/// Инфо о кустах
/// </summary>
[Route("api/cluster")]
[ApiController]
[Authorize]
public class ClusterController : ControllerBase
{
private readonly IClusterService clusterService;
public ClusterController(IClusterService clusterService)
{
this.clusterService = clusterService;
}
/// <summary>
/// Получает список доступных пользователю кустов
/// </summary>
/// <param name="token"> Токен отмены задачи </param>
/// <returns></returns>
[HttpGet()]
[Permission]
[ProducesResponseType(typeof(IEnumerable<ClusterDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetClustersAsync(CancellationToken token = default)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
var result = await clusterService.GetClustersAsync((int)idCompany,
token).ConfigureAwait(false);
return Ok(result);
}
/// <summary>
/// Получение доступных пользователю скважин
/// </summary>
/// <param name="idCluster"></param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns></returns>
[HttpGet("{idCluster}")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<WellDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetWellsAsync(int idCluster, CancellationToken token = default)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
var result = await clusterService.GetWellsAsync((int)idCompany,
idCluster, token).ConfigureAwait(false);
return Ok(result);
}
}
}

View File

@ -1,5 +1,5 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Services; using AsbCloudApp.Repositories;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
@ -16,11 +16,11 @@ namespace AsbCloudWebApi.Controllers
[Authorize] [Authorize]
public class DepositController : ControllerBase public class DepositController : ControllerBase
{ {
private readonly IClusterService clusterService; private readonly IDepositRepository depositService;
public DepositController(IClusterService clusterService) public DepositController(IDepositRepository depositService)
{ {
this.clusterService = clusterService; this.depositService = depositService;
} }
/// <summary> /// <summary>
@ -38,7 +38,7 @@ namespace AsbCloudWebApi.Controllers
if (idCompany is null) if (idCompany is null)
return Forbid(); return Forbid();
var result = await clusterService.GetDepositsAsync((int)idCompany, var result = await depositService.GetAsync((int)idCompany,
token).ConfigureAwait(false); token).ConfigureAwait(false);
return Ok(result); return Ok(result);
} }
@ -58,7 +58,7 @@ namespace AsbCloudWebApi.Controllers
if (idCompany is null) if (idCompany is null)
return Forbid(); return Forbid();
var result = await clusterService.GetDepositsDrillParamsAsync((int)idCompany, var result = await depositService.GetAllWithDrillParamsAsync((int)idCompany,
token).ConfigureAwait(false); token).ConfigureAwait(false);
return Ok(result); return Ok(result);
} }
@ -80,7 +80,7 @@ namespace AsbCloudWebApi.Controllers
if (idCompany is null) if (idCompany is null)
return Forbid(); return Forbid();
var result = await clusterService.GetClustersAsync((int)idCompany, var result = await depositService.GetClustersAsync((int)idCompany,
depositId, token).ConfigureAwait(false); depositId, token).ConfigureAwait(false);
return Ok(result); return Ok(result);
} }

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
namespace AsbCloudWebApi.Controllers namespace AsbCloudWebApi.Controllers
{ {
#nullable enable
/// <summary> /// <summary>
/// Мониторинг запросов, ошибок, пользователей /// Мониторинг запросов, ошибок, пользователей
/// </summary> /// </summary>
@ -87,4 +88,5 @@ namespace AsbCloudWebApi.Controllers
return Ok(result); return Ok(result);
} }
} }
#nullable disable
} }

View File

@ -1,9 +1,9 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
@ -11,6 +11,7 @@ using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers namespace AsbCloudWebApi.Controllers
{ {
#nullable enable
/// <summary> /// <summary>
/// Буровые операции (вводимые вручную) /// Буровые операции (вводимые вручную)
/// </summary> /// </summary>
@ -44,7 +45,6 @@ namespace AsbCloudWebApi.Controllers
return Ok(result); return Ok(result);
} }
/// <summary> /// <summary>
/// Возвращает список имен типов операций на скважине /// Возвращает список имен типов операций на скважине
/// </summary> /// </summary>
@ -63,15 +63,7 @@ namespace AsbCloudWebApi.Controllers
/// Отфильтрованный список операций на скважине. Если не применять фильтр, то вернется весь список. Сортированный по глубине затем по дате /// Отфильтрованный список операций на скважине. Если не применять фильтр, то вернется весь список. Сортированный по глубине затем по дате
/// </summary> /// </summary>
/// <param name="idWell">id скважины</param> /// <param name="idWell">id скважины</param>
/// <param name="opertaionType">фильтр по план = 0, факт = 1</param> /// <param name="request"></param>
/// <param name="sectionTypeIds">фильтр по списку id конструкций секции</param>
/// <param name="operationCategoryIds">фильтр по списку id категорий операции</param>
/// <param name="begin">фильтр по началу операции</param>
/// <param name="end">фильтр по окончанию операции</param>
/// <param name="minDepth">фильтр по минимальной глубине скважины</param>
/// <param name="maxDepth">фильтр по максимальной глубине скважины</param>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns>Список операций на скважине в контейнере для постраничного просмотра</returns> /// <returns>Список операций на скважине в контейнере для постраничного просмотра</returns>
[HttpGet] [HttpGet]
@ -79,31 +71,15 @@ namespace AsbCloudWebApi.Controllers
[ProducesResponseType(typeof(PaginationContainer<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(PaginationContainer<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetOperationsAsync( public async Task<IActionResult> GetOperationsAsync(
[FromRoute] int idWell, [FromRoute] int idWell,
[FromQuery] int? opertaionType = default, [FromQuery] WellOperationRequestBase request,
[FromQuery] IEnumerable<int> sectionTypeIds = default, CancellationToken token)
[FromQuery] IEnumerable<int> operationCategoryIds = default,
[FromQuery] DateTime begin = default,
[FromQuery] DateTime end = default,
[FromQuery] double minDepth = double.MinValue,
[FromQuery] double maxDepth = double.MaxValue,
[FromQuery] int skip = 0,
[FromQuery] int take = 32,
CancellationToken token = default)
{ {
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid(); return Forbid();
var requestToService = new WellOperationRequest(request, idWell);
var result = await operationService.GetOperationsAsync( var result = await operationService.GetOperationsAsync(
idWell, requestToService,
opertaionType,
sectionTypeIds,
operationCategoryIds,
begin,
end,
minDepth,
maxDepth,
skip,
take,
token) token)
.ConfigureAwait(false); .ConfigureAwait(false);
return Ok(result); return Ok(result);
@ -113,13 +89,7 @@ namespace AsbCloudWebApi.Controllers
/// Статистика операций по скважине, группированая по категориям /// Статистика операций по скважине, группированая по категориям
/// </summary> /// </summary>
/// <param name="idWell">id скважины</param> /// <param name="idWell">id скважины</param>
/// <param name="opertaionType"></param> /// <param name="request"></param>
/// <param name="sectionTypeIds"></param>
/// <param name="operationCategoryIds"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="minDepth"></param>
/// <param name="maxDepth"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
[HttpGet] [HttpGet]
@ -128,27 +98,15 @@ namespace AsbCloudWebApi.Controllers
[ProducesResponseType(typeof(IEnumerable<WellGroupOpertionDto>), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable<WellGroupOpertionDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetGroupOperationsAsync( public async Task<IActionResult> GetGroupOperationsAsync(
[FromRoute] int idWell, [FromRoute] int idWell,
[FromQuery] int? opertaionType = default, [FromQuery] WellOperationRequestBase request,
[FromQuery] IEnumerable<int> sectionTypeIds = default, CancellationToken token)
[FromQuery] IEnumerable<int> operationCategoryIds = default,
[FromQuery] DateTime begin = default,
[FromQuery] DateTime end = default,
[FromQuery] double minDepth = double.MinValue,
[FromQuery] double maxDepth = double.MaxValue,
CancellationToken token = default)
{ {
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid(); return Forbid();
var requestToService = new WellOperationRequest(request, idWell);
var result = await operationService.GetGroupOperationsStatAsync( var result = await operationService.GetGroupOperationsStatAsync(
idWell, requestToService,
opertaionType,
sectionTypeIds,
operationCategoryIds,
begin,
end,
minDepth,
maxDepth,
token) token)
.ConfigureAwait(false); .ConfigureAwait(false);
return Ok(result); return Ok(result);
@ -165,8 +123,8 @@ namespace AsbCloudWebApi.Controllers
[Route("{idOperation}")] [Route("{idOperation}")]
[Permission] [Permission]
[ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetAsync(int idWell, int idOperation, public async Task<IActionResult> GetOrDefaultAsync(int idWell, int idOperation,
CancellationToken token = default) CancellationToken token)
{ {
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid(); return Forbid();
@ -186,13 +144,17 @@ namespace AsbCloudWebApi.Controllers
[Permission] [Permission]
[ProducesResponseType(typeof(IEnumerable<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable<WellOperationDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> InsertRangeAsync(int idWell, [FromBody] IEnumerable<WellOperationDto> values, public async Task<IActionResult> InsertRangeAsync(int idWell, [FromBody] IEnumerable<WellOperationDto> values,
CancellationToken token = default) CancellationToken token)
{ {
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid(); return Forbid();
var result = await operationService.InsertRangeAsync(idWell, values, token) foreach(var value in values)
value.IdWell= idWell;
var result = await operationService.InsertRangeAsync(values, token)
.ConfigureAwait(false); .ConfigureAwait(false);
return Ok(result); return Ok(result);
} }
@ -208,12 +170,15 @@ namespace AsbCloudWebApi.Controllers
[Permission] [Permission]
[ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(WellOperationDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> UpdateAsync(int idWell, int idOperation, public async Task<IActionResult> UpdateAsync(int idWell, int idOperation,
[FromBody] WellOperationDto value, CancellationToken token = default) [FromBody] WellOperationDto value, CancellationToken token)
{ {
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid(); return Forbid();
var result = await operationService.UpdateAsync(idWell, idOperation, value, token) value.IdWell= idWell;
value.Id = idOperation;
var result = await operationService.UpdateAsync(value, token)
.ConfigureAwait(false); .ConfigureAwait(false);
return Ok(result); return Ok(result);
} }
@ -228,7 +193,7 @@ namespace AsbCloudWebApi.Controllers
[HttpDelete("{idOperation}")] [HttpDelete("{idOperation}")]
[Permission] [Permission]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> DeleteAsync(int idWell, int idOperation, CancellationToken token = default) public async Task<IActionResult> DeleteAsync(int idWell, int idOperation, CancellationToken token)
{ {
if (!await CanUserAccessToWellAsync(idWell, if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false)) token).ConfigureAwait(false))
@ -254,8 +219,8 @@ namespace AsbCloudWebApi.Controllers
[Route("import/{options}")] [Route("import/{options}")]
public async Task<IActionResult> ImportAsync(int idWell, public async Task<IActionResult> ImportAsync(int idWell,
[FromForm] IFormFileCollection files, [FromForm] IFormFileCollection files,
int options = 0, int options,
CancellationToken token = default) CancellationToken token)
{ {
int? idCompany = User.GetCompanyId(); int? idCompany = User.GetCompanyId();
int? idUser = User.GetUserId(); int? idUser = User.GetUserId();
@ -297,7 +262,7 @@ namespace AsbCloudWebApi.Controllers
[Route("export")] [Route("export")]
[Permission] [Permission]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> ExportAsync([FromRoute] int idWell, CancellationToken token = default) public async Task<IActionResult> ExportAsync([FromRoute] int idWell, CancellationToken token)
{ {
int? idCompany = User.GetCompanyId(); int? idCompany = User.GetCompanyId();
@ -324,7 +289,7 @@ namespace AsbCloudWebApi.Controllers
[Route("scheduleReport")] [Route("scheduleReport")]
[Permission] [Permission]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> ScheduleReportAsync([FromRoute] int idWell, [FromServices] IScheduleReportService scheduleReportService, CancellationToken token = default) public async Task<IActionResult> ScheduleReportAsync([FromRoute] int idWell, [FromServices] IScheduleReportService scheduleReportService, CancellationToken token)
{ {
int? idCompany = User.GetCompanyId(); int? idCompany = User.GetCompanyId();
@ -355,11 +320,12 @@ namespace AsbCloudWebApi.Controllers
return File(stream, "application/octet-stream", fileName); return File(stream, "application/octet-stream", fileName);
} }
private async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken token = default) private async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken token)
{ {
int? idCompany = User.GetCompanyId(); int? idCompany = User.GetCompanyId();
return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false); idWell, token).ConfigureAwait(false);
} }
} }
#nullable disable
} }

View File

@ -4,6 +4,7 @@ using System.Threading.Tasks;
namespace AsbCloudWebApi.Middlewares namespace AsbCloudWebApi.Middlewares
{ {
#nullable enable
public class RequerstTrackerMiddleware public class RequerstTrackerMiddleware
{ {
private readonly RequestDelegate next; private readonly RequestDelegate next;
@ -18,8 +19,8 @@ namespace AsbCloudWebApi.Middlewares
var service = context.RequestServices.GetRequiredService<AsbCloudApp.Services.IRequerstTrackerService>(); var service = context.RequestServices.GetRequiredService<AsbCloudApp.Services.IRequerstTrackerService>();
var requestLog = new AsbCloudApp.Data.RequestLogDto var requestLog = new AsbCloudApp.Data.RequestLogDto
{ {
UserLogin = context.User?.Identity.Name, UserLogin = context.User.Identity?.Name ?? string.Empty,
UserIp = context.Connection.RemoteIpAddress.ToString(), UserIp = context.Connection?.RemoteIpAddress?.ToString(),
RequestMethod = context.Request.Method, RequestMethod = context.Request.Method,
RequestPath = context.Request.Path.Value, RequestPath = context.Request.Path.Value,
Referer = context.Request.Headers["Referer"].ToString(), Referer = context.Request.Headers["Referer"].ToString(),
@ -32,7 +33,7 @@ namespace AsbCloudWebApi.Middlewares
var sw = System.Diagnostics.Stopwatch.StartNew(); var sw = System.Diagnostics.Stopwatch.StartNew();
try try
{ {
await next?.Invoke(context); await next.Invoke(context);
sw.Stop(); sw.Stop();
requestLog.ElapsedMilliseconds = sw.ElapsedMilliseconds; requestLog.ElapsedMilliseconds = sw.ElapsedMilliseconds;
requestLog.Status = context.Response.StatusCode; requestLog.Status = context.Response.StatusCode;
@ -43,10 +44,10 @@ namespace AsbCloudWebApi.Middlewares
sw.Stop(); sw.Stop();
requestLog.ElapsedMilliseconds = sw.ElapsedMilliseconds; requestLog.ElapsedMilliseconds = sw.ElapsedMilliseconds;
requestLog.Status = context.Response.StatusCode; requestLog.Status = context.Response.StatusCode;
// TODO: Add request params and body size.
service.RegisterRequestError(requestLog, ex); service.RegisterRequestError(requestLog, ex);
throw; throw;
} }
} }
} }
#nullable disable
} }

View File

@ -32,7 +32,7 @@ namespace AsbCloudWebApi.Middlewares
controllerNames = configuration.GetSection("userLimits")?.GetValue<IEnumerable<string>>("controllerNames"); controllerNames = configuration.GetSection("userLimits")?.GetValue<IEnumerable<string>>("controllerNames");
var bodyText = $"<html><head><title>Too Many Requests</title></head><body><h1>Too Many Requests</h1><p>I only allow {parallelRequestsToController} parallel requests per user. Try again soon.</p></body></html>"; var bodyText = $"<html><head><title>Too Many Requests</title></head><body><h1>Too Many Requests</h1><p>I only allow {this.parallelRequestsToController} parallel requests per user. Try again soon.</p></body></html>";
responseBody = System.Text.Encoding.UTF8.GetBytes(bodyText); responseBody = System.Text.Encoding.UTF8.GetBytes(bodyText);
} }

View File

@ -13,9 +13,9 @@
"LocalConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True" "LocalConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True"
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"userLimits": { //"userLimits": {
"parallelRequestsToController": 5 // "parallelRequestsToController": 5
}, //},
"email": { "email": {
"smtpServer": "smtp.timeweb.ru", "smtpServer": "smtp.timeweb.ru",
"sender": "bot@autodrilling.ru", "sender": "bot@autodrilling.ru",