From c4bb5f90407395aef884882582c86c6e97f00b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 4 Apr 2024 07:41:00 +0300 Subject: [PATCH 1/5] =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BE?= =?UTF-8?q?=D1=82=20=D0=93=D0=A2=D0=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Добавлен новый Dto 2. Обновлён репозиторий 3. Обновление API --- AsbCloudApp/Data/GTR/GtrWitsDto.cs | 214 ++++++++++++++++++ AsbCloudApp/Repositories/IGtrRepository.cs | 12 + ...GtrWithGetDataRequest.cs => GtrRequest.cs} | 19 +- .../Repository/GtrWitsRepository.cs | 89 ++++++++ .../Clients/IGtrWitsClient.cs | 13 ++ .../Controllers/GtrControllerTests.cs | 68 ++++++ .../Controllers/GtrWitsController.cs | 65 ++++++ .../Controllers/SAUB/GtrWitsController.cs | 2 +- 8 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 AsbCloudApp/Data/GTR/GtrWitsDto.cs rename AsbCloudApp/Requests/{GtrWithGetDataRequest.cs => GtrRequest.cs} (63%) create mode 100644 AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs create mode 100644 AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs create mode 100644 AsbCloudWebApi/Controllers/GtrWitsController.cs diff --git a/AsbCloudApp/Data/GTR/GtrWitsDto.cs b/AsbCloudApp/Data/GTR/GtrWitsDto.cs new file mode 100644 index 00000000..a8ecb939 --- /dev/null +++ b/AsbCloudApp/Data/GTR/GtrWitsDto.cs @@ -0,0 +1,214 @@ +namespace AsbCloudApp.Data.GTR; + +public class GtrWitsDto +{ + /// + /// Вес на крюке + /// + public float? HKLA { get; set; } + + /// + /// Высота крюка + /// + public float? BLKPOS { get; set; } + + /// + /// Нагрузка на долото + /// + public float? WOBA { get; set; } + + /// + /// Момент на роторе/ВСП + /// + public float? TORQA { get; set; } + + /// + /// Давление на входе (на стояке) + /// + public float? SPPA { get; set; } + + /// + /// Обороты ротора/ВСП + /// + public float? RPMA { get; set; } + + /// + /// Механическая скорость + /// + public float? ROPA { get; set; } + + /// + /// Скорость инструмента вверх + /// + public float? RSUX { get; set; } + + /// + /// Скорость инструмента вниз + /// + public float? RSDX { get; set; } + + /// + /// Расход на входе + /// + public float? MFIA { get; set; } + + /// + /// Расход на выходе + /// + public float? MFOA { get; set; } + + /// + /// Температура на входе + /// + public float? MTIA { get; set; } + + /// + /// Температура на выходе + /// + public float? MTOA { get; set; } + + /// + /// Ходы насоса №1 + /// + public float? SPM1 { get; set; } + + /// + /// Ходы насоса №2 + /// + public float? SPM2 { get; set; } + + /// + /// Ходы насоса №3 + /// + public float? SPM3 { get; set; } + + /// + /// Общий объем бурового раствора на поверхности + /// + public float? TVOLACT { get; set; } + + /// + /// Объем бурового раствора в доливной емкости №1 + /// + public float? TTVOL1 { get; set; } + + /// + /// Объем бурового раствора в доливной емкости №2 + /// + public float? TTVOL2 { get; set; } + + /// + /// Объем бурового раствора в емкости №1 + /// + public float? TVOL01 { get; set; } + + /// + /// Объем бурового раствора в емкости №2 + /// + public float? TVOL02 { get; set; } + + /// + /// Объем бурового раствора в емкости №3 + /// + public float? TVOL03 { get; set; } + + /// + /// Объем бурового раствора в емкости №4 + /// + public float? TVOL04 { get; set; } + + /// + /// Объем бурового раствора в емкости №5 + /// + public float? TVOL05 { get; set; } + + /// + /// Объем бурового раствора в емкости №6 + /// + public float? TVOL06 { get; set; } + + /// + /// Объем бурового раствора в емкости №7 + /// + public float? TVOL07 { get; set; } + + /// + /// Объем бурового раствора в емкости №8 + /// + public float? TVOL08 { get; set; } + + /// + /// Объем бурового раствора в емкости №9 + /// + public float? TVOL09 { get; set; } + + /// + /// Объем бурового раствора в емкости №10 + /// + public float? TVOL10 { get; set; } + + /// + /// Объем бурового раствора в емкости №11 + /// + public float? TVOL11 { get; set; } + + /// + /// Объем бурового раствора в емкости №12 + /// + public float? TVOL12 { get; set; } + + /// + /// Объем бурового раствора в емкости №13 + /// + public float? TVOL13 { get; set; } + + /// + /// Объем бурового раствора в емкости №14 + /// + public float? TVOL14 { get; set; } + + /// + /// Плотность (удельный вес) бурового раствора на выходе + /// + public float? MDOA { get; set; } + + /// + /// Плотность (удельный вес) бурового раствора на входе + /// + public float? MDIA { get; set; } + + /// + /// Процентное содержание метана + /// + public float? METHANE { get; set; } + + /// + /// Процентное содержание этана + /// + public float? ETHANE { get; set; } + + /// + /// Процентное содержание пропана + /// + public float? PROPANE { get; set; } + + /// + /// Процентное содержание бутана + /// + public float? IBUTANE { get; set; } + + /// + /// Процентное содержание пентана + /// + public float? NBUTANE { get; set; } + + /// + /// Процентное содержание углеводородов + /// + public float? HydrocarbonPercentage => METHANE + ETHANE + PROPANE + IBUTANE + NBUTANE; + + /// + /// Процентное содержание газов + /// + public float? GASA { get; set; } +} \ No newline at end of file diff --git a/AsbCloudApp/Repositories/IGtrRepository.cs b/AsbCloudApp/Repositories/IGtrRepository.cs index 0d597dde..1aadfb96 100644 --- a/AsbCloudApp/Repositories/IGtrRepository.cs +++ b/AsbCloudApp/Repositories/IGtrRepository.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Requests; namespace AsbCloudApp.Repositories { @@ -19,6 +20,14 @@ namespace AsbCloudApp.Repositories /// /// Task SaveDataAsync(int idTelemetry, IEnumerable dtos, CancellationToken token); + + /// + /// получить данные ГТИ + /// + /// + /// + /// + Task> GetAsync(GtrRequest request, CancellationToken token); /// /// получить данные для клиента @@ -29,6 +38,7 @@ namespace AsbCloudApp.Repositories /// кол-во элементов до которых эти данные прореживаются /// /// + [Obsolete] Task> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default); @@ -39,6 +49,7 @@ namespace AsbCloudApp.Repositories /// /// /// + [Obsolete] IEnumerable GetLastDataByRecordId(int idWell, int idRecord); /// @@ -46,6 +57,7 @@ namespace AsbCloudApp.Repositories /// /// /// + [Obsolete] IEnumerable GetLastData(int idWell); } } diff --git a/AsbCloudApp/Requests/GtrWithGetDataRequest.cs b/AsbCloudApp/Requests/GtrRequest.cs similarity index 63% rename from AsbCloudApp/Requests/GtrWithGetDataRequest.cs rename to AsbCloudApp/Requests/GtrRequest.cs index 8e93a02c..8ba678b2 100644 --- a/AsbCloudApp/Requests/GtrWithGetDataRequest.cs +++ b/AsbCloudApp/Requests/GtrRequest.cs @@ -5,7 +5,7 @@ namespace AsbCloudApp.Requests; /// /// Параметры запроса для получения загруженных данных ГТИ по скважине /// -public class GtrWithGetDataRequest +public class GtrRequestBase { /// /// Дата начала выборки.По умолчанию: текущее время - IntervalSec @@ -20,5 +20,22 @@ public class GtrWithGetDataRequest /// /// Желаемое количество точек. Если в выборке точек будет больше, то выборка будет прорежена. /// + [Obsolete] public int ApproxPointsCount { get; set; } = 1024; +} + +/// +/// Параметры запроса для получения загруженных данных ГТИ по скважине +/// +public class GtrRequest : GtrRequestBase +{ + public GtrRequest(int idWell, GtrRequestBase request) + { + IdWell = idWell; + Begin = request.Begin; + IntervalSec = request.IntervalSec; + ApproxPointsCount = request.ApproxPointsCount; + } + + public int IdWell { get; set; } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs index 2a871553..5d0cda7b 100644 --- a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs +++ b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs @@ -12,11 +12,58 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Requests; +using Mapster; namespace AsbCloudInfrastructure.Repository { public class GtrWitsRepository : IGtrRepository { + private static IDictionary<(int, int), string> WitsParameters = new Dictionary<(int, int), string> + { + { (1, 14), nameof(GtrWitsDto.HKLA) }, + { (1, 12), nameof(GtrWitsDto.BLKPOS) }, + { (1, 16), nameof(GtrWitsDto.WOBA) }, + { (1, 18), nameof(GtrWitsDto.TORQA) }, + { (1, 21), nameof(GtrWitsDto.SPPA) }, + { (2, 15), nameof(GtrWitsDto.RPMA) }, + { (1, 13), nameof(GtrWitsDto.ROPA) }, + { (3, 16), nameof(GtrWitsDto.RSUX) }, + { (3, 17), nameof(GtrWitsDto.RSDX) }, + { (1, 30), nameof(GtrWitsDto.MFIA) }, + { (1, 29), nameof(GtrWitsDto.MFOA)}, + { (1, 34), nameof(GtrWitsDto.MTIA) }, + { (1, 33), nameof(GtrWitsDto.MTOA) }, + { (1, 23), nameof(GtrWitsDto.SPM1) }, + { (1, 24), nameof(GtrWitsDto.SPM2) }, + { (1, 25), nameof(GtrWitsDto.SPM3) }, + { (1, 26), nameof(GtrWitsDto.TVOLACT) }, + { (11, 29), nameof(GtrWitsDto.TTVOL1) }, + { (11, 30), nameof(GtrWitsDto.TTVOL2) }, + { (11, 15), nameof(GtrWitsDto.TVOL01) }, + { (11, 16), nameof(GtrWitsDto.TVOL02) }, + { (11, 17), nameof(GtrWitsDto.TVOL03) }, + { (11, 18), nameof(GtrWitsDto.TVOL04) }, + { (11, 19), nameof(GtrWitsDto.TVOL05) }, + { (11, 20), nameof(GtrWitsDto.TVOL06) }, + { (11, 21), nameof(GtrWitsDto.TVOL07) }, + { (11, 22), nameof(GtrWitsDto.TVOL08) }, + { (11, 23), nameof(GtrWitsDto.TVOL09) }, + { (11, 24), nameof(GtrWitsDto.TVOL10) }, + { (11, 25), nameof(GtrWitsDto.TVOL11) }, + { (11, 26), nameof(GtrWitsDto.TVOL12) }, + { (11, 27), nameof(GtrWitsDto.TVOL13) }, + { (11, 28), nameof(GtrWitsDto.TVOL14) }, + { (1, 31), nameof(GtrWitsDto.MDOA) }, + { (1, 32), nameof(GtrWitsDto.MDIA) }, + { (12, 12), nameof(GtrWitsDto.METHANE) }, + { (12, 13), nameof(GtrWitsDto.ETHANE) }, + { (12, 14), nameof(GtrWitsDto.PROPANE) }, + { (12, 15), nameof(GtrWitsDto.IBUTANE) }, + { (12, 16), nameof(GtrWitsDto.NBUTANE) }, + { (1, 40), nameof(GtrWitsDto.GASA) }, + }; + private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; private static ConcurrentDictionary> cache = new(); @@ -28,6 +75,48 @@ namespace AsbCloudInfrastructure.Repository this.db = db; this.telemetryService = telemetryService; } + + public async Task> GetAsync(GtrRequest request, CancellationToken token) + { + var interval = TimeSpan.FromSeconds(10); + var query = BuildQuery(request); + var entities = await query.AsNoTracking().ToArrayAsync(token); + + var dtos = entities + .GroupBy(e => e.DateTime.Ticks / interval.Ticks) + .Select(Convert); + + return dtos; + } + + private static GtrWitsDto Convert(IEnumerable scr) + { + var values = scr.GroupBy(e => (e.IdRecord, e.IdItem)) + .ToDictionary(g => WitsParameters[g.Key], g => g.LastOrDefault()?.Value); + + var dto = values.Adapt(); + + return dto; + } + + private IQueryable BuildQuery(GtrRequest request) + where TEntity : WitsItemBase + where TType : notnull + { + var query = db.Set().OrderBy(e => e.DateTime) + .Where(e => e.Telemetry != null && + e.Telemetry.Well != null && + e.Telemetry.Well.Id == request.IdWell) + .Where(e => e.DateTime >= DateTime.UtcNow.AddSeconds(-request.IntervalSec)); + + if (request.Begin.HasValue) + { + var dateBeginUtc = request.Begin.Value.ToUniversalTime(); + query = query.Where(e => e.DateTime >= dateBeginUtc); + } + + return query; + } public async Task> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) { diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs new file mode 100644 index 00000000..17f76a33 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs @@ -0,0 +1,13 @@ +using AsbCloudApp.Data.GTR; +using AsbCloudApp.Requests; +using Refit; + +namespace AsbCloudWebApi.IntegrationTests.Clients; + +public interface IGtrWitsClient +{ + private const string BaseRoute = "/api/well/{idWell}/gtrWits"; + + [Get(BaseRoute)] + Task>> GetAllAsync(int idWell, [Query] GtrRequestBase request); +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs b/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs new file mode 100644 index 00000000..eb1e96d8 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs @@ -0,0 +1,68 @@ +using System.Net; +using AsbCloudApp.Requests; +using AsbCloudDb.Model.GTR; +using AsbCloudWebApi.IntegrationTests.Clients; +using Xunit; + +namespace AsbCloudWebApi.IntegrationTests.Controllers; + +public class GtrControllerTests : BaseIntegrationTest +{ + private readonly IGtrWitsClient client; + + public GtrControllerTests(WebAppFactoryFixture factory) + : base(factory) + { + client = factory.GetAuthorizedHttpClient(string.Empty); + } + + [Fact] + public async Task GetAll_returns_success() + { + //arrange + var well = dbContext.Wells.First(); + + var witsItems = CreateWitsItems(well.IdTelemetry!.Value); + dbContext.WitsItemFloat.AddRange(witsItems); + await dbContext.SaveChangesAsync(); + + var request = new GtrRequestBase(); + + //act + var response = await client.GetAllAsync(well.Id, request); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.True(response.Content.Any()); + } + + private static IEnumerable CreateWitsItems(int idTelemetry) => + new[] + { + new WitsItemFloat + { + IdRecord = 1, + IdItem = 14, + Value = 4, + IdTelemetry = idTelemetry, + DateTime = DateTimeOffset.UtcNow + }, + new WitsItemFloat + { + IdRecord = 1, + IdItem = 14, + Value = 5, + IdTelemetry = idTelemetry, + DateTime = DateTimeOffset.UtcNow + }, + new WitsItemFloat + { + IdRecord = 1, + IdItem = 12, + Value = 5, + IdTelemetry = idTelemetry, + DateTime = DateTimeOffset.UtcNow.AddSeconds(10) + } + }; +} \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/GtrWitsController.cs b/AsbCloudWebApi/Controllers/GtrWitsController.cs new file mode 100644 index 00000000..69d8a7d2 --- /dev/null +++ b/AsbCloudWebApi/Controllers/GtrWitsController.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using AsbCloudApp.Data.GTR; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace AsbCloudWebApi.Controllers; + +[ApiController] +[Route("api/well/{idWell}/[controller]")] +[Authorize] +public class GtrWitsController : ControllerBase +{ + private readonly IWellService wellService; + private readonly IGtrRepository gtrRepository; + + public GtrWitsController(IWellService wellService, + IGtrRepository gtrRepository) + { + this.wellService = wellService; + this.gtrRepository = gtrRepository; + } + + /// + /// Получить значение от ГТИ + /// + /// + /// + /// + /// + [HttpGet] + [Permission] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task GetAllAsync(int idWell, [FromQuery] GtrRequestBase request, CancellationToken token) + { + await AssertUserHasAccessToWellAsync(idWell, token); + + var requestToRepository = new GtrRequest(idWell, request); + + var dtos = await gtrRepository.GetAsync(requestToRepository, token); + + return Ok(dtos); + } + + private async Task AssertUserHasAccessToWellAsync(int idWell, CancellationToken token) + { + var idUser = User.GetUserId(); + var idCompany = User.GetCompanyId(); + + if (!idUser.HasValue) + throw new ForbidException("Нет доступа к скважине"); + + if (!idCompany.HasValue) + throw new ForbidException("Нет доступа к скважине"); + + if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token)) + throw new ForbidException("Нет доступа к скважине"); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs index f4cfe0b4..95662fe2 100644 --- a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs @@ -46,7 +46,7 @@ namespace AsbCloudWebApi.Controllers.SAUB /// [HttpGet("{idWell}")] public async Task>> GetDataAsync([Required] int idWell, - [FromQuery] GtrWithGetDataRequest request, + [FromQuery] GtrRequest request, CancellationToken token) { int? idCompany = User.GetCompanyId(); From 979ed91e786f7e027a64c2b093d3a4eb0c665eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 8 Apr 2024 14:32:00 +0300 Subject: [PATCH 2/5] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Data/GTR/GtrWitsDto.cs | 20 ++++++ AsbCloudApp/Repositories/IGtrRepository.cs | 3 +- AsbCloudApp/Requests/GtrRequest.cs | 18 +---- .../Repository/GtrWitsRepository.cs | 68 +++++++++++++------ .../Clients/IGtrWitsClient.cs | 4 +- .../Controllers/GtrControllerTests.cs | 2 +- .../Controllers/GtrWitsController.cs | 65 ------------------ .../Controllers/SAUB/GtrWitsController.cs | 36 ++++++++++ 8 files changed, 108 insertions(+), 108 deletions(-) delete mode 100644 AsbCloudWebApi/Controllers/GtrWitsController.cs diff --git a/AsbCloudApp/Data/GTR/GtrWitsDto.cs b/AsbCloudApp/Data/GTR/GtrWitsDto.cs index a8ecb939..20d08dd6 100644 --- a/AsbCloudApp/Data/GTR/GtrWitsDto.cs +++ b/AsbCloudApp/Data/GTR/GtrWitsDto.cs @@ -1,7 +1,27 @@ +using System; + namespace AsbCloudApp.Data.GTR; +/// +/// ГТИ +/// public class GtrWitsDto { + /// + /// Дата получения записи + /// + public DateTimeOffset DateTime { get; set; } + + /// + /// Забой (скважины), м + /// + public float? DEPTMEAS { get; set; } + + /// + /// Долото, м + /// + public float DEPTBITM { get; set; } + /// /// Вес на крюке /// diff --git a/AsbCloudApp/Repositories/IGtrRepository.cs b/AsbCloudApp/Repositories/IGtrRepository.cs index 1aadfb96..706b6be2 100644 --- a/AsbCloudApp/Repositories/IGtrRepository.cs +++ b/AsbCloudApp/Repositories/IGtrRepository.cs @@ -24,10 +24,11 @@ namespace AsbCloudApp.Repositories /// /// получить данные ГТИ /// + /// /// /// /// - Task> GetAsync(GtrRequest request, CancellationToken token); + Task> GetAsync(int idWell, GtrRequest request, CancellationToken token); /// /// получить данные для клиента diff --git a/AsbCloudApp/Requests/GtrRequest.cs b/AsbCloudApp/Requests/GtrRequest.cs index 8ba678b2..43de25c4 100644 --- a/AsbCloudApp/Requests/GtrRequest.cs +++ b/AsbCloudApp/Requests/GtrRequest.cs @@ -5,7 +5,7 @@ namespace AsbCloudApp.Requests; /// /// Параметры запроса для получения загруженных данных ГТИ по скважине /// -public class GtrRequestBase +public class GtrRequest { /// /// Дата начала выборки.По умолчанию: текущее время - IntervalSec @@ -22,20 +22,4 @@ public class GtrRequestBase /// [Obsolete] public int ApproxPointsCount { get; set; } = 1024; -} - -/// -/// Параметры запроса для получения загруженных данных ГТИ по скважине -/// -public class GtrRequest : GtrRequestBase -{ - public GtrRequest(int idWell, GtrRequestBase request) - { - IdWell = idWell; - Begin = request.Begin; - IntervalSec = request.IntervalSec; - ApproxPointsCount = request.ApproxPointsCount; - } - - public int IdWell { get; set; } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs index 5d0cda7b..022532f2 100644 --- a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs +++ b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs @@ -21,6 +21,8 @@ namespace AsbCloudInfrastructure.Repository { private static IDictionary<(int, int), string> WitsParameters = new Dictionary<(int, int), string> { + { (1, 8), nameof(GtrWitsDto.DEPTBITM) }, + { (1, 10), nameof(GtrWitsDto.DEPTMEAS) }, { (1, 14), nameof(GtrWitsDto.HKLA) }, { (1, 12), nameof(GtrWitsDto.BLKPOS) }, { (1, 16), nameof(GtrWitsDto.WOBA) }, @@ -75,39 +77,60 @@ namespace AsbCloudInfrastructure.Repository this.db = db; this.telemetryService = telemetryService; } - - public async Task> GetAsync(GtrRequest request, CancellationToken token) + + public async Task> GetAsync(int idWell, GtrRequest request, CancellationToken token) => + await GetAsync(idWell, request, token); + + private async Task> GetAsync(int idWell, GtrRequest request, CancellationToken token) + where TEntity : WitsItemBase + where TType : notnull { - var interval = TimeSpan.FromSeconds(10); - var query = BuildQuery(request); - var entities = await query.AsNoTracking().ToArrayAsync(token); + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); + if (telemetry is null) + return Enumerable.Empty(); + + var timezone = telemetryService.GetTimezone(telemetry.Id); + var timezoneOffset = TimeSpan.FromHours(timezone.Hours); + + var query = BuildQuery(telemetry.Id, request); + + if (!await query.AnyAsync(token)) + return Enumerable.Empty(); + + var interval = TimeSpan.FromSeconds(10); + + var entities = await query + .OrderBy(e => e.DateTime) + .AsNoTracking() + .ToArrayAsync(token); + var dtos = entities .GroupBy(e => e.DateTime.Ticks / interval.Ticks) - .Select(Convert); + .Select(groupByInterval => + { + var items = groupByInterval.Select(e => e); + var values = items.GroupBy(e => (e.IdRecord, e.IdItem)) + .Where(parameter => parameter.Any()) + .ToDictionary(parameter => WitsParameters[parameter.Key], g => g.Last().Value.ToString()); + + var dto = values.Adapt(); + dto.DateTime = items.Last().DateTime.ToOffset(timezoneOffset); + return dto; + }); return dtos; } - private static GtrWitsDto Convert(IEnumerable scr) - { - var values = scr.GroupBy(e => (e.IdRecord, e.IdItem)) - .ToDictionary(g => WitsParameters[g.Key], g => g.LastOrDefault()?.Value); - - var dto = values.Adapt(); - - return dto; - } - - private IQueryable BuildQuery(GtrRequest request) + private IQueryable BuildQuery(int idTelemetry, GtrRequest request) where TEntity : WitsItemBase where TType : notnull { - var query = db.Set().OrderBy(e => e.DateTime) - .Where(e => e.Telemetry != null && - e.Telemetry.Well != null && - e.Telemetry.Well.Id == request.IdWell) - .Where(e => e.DateTime >= DateTime.UtcNow.AddSeconds(-request.IntervalSec)); + var dateIntervalStart = DateTime.UtcNow.AddSeconds(-request.IntervalSec); + + var query = db.Set() + .Where(e => e.IdTelemetry == idTelemetry) + .Where(e => e.DateTime >= dateIntervalStart); if (request.Begin.HasValue) { @@ -118,6 +141,7 @@ namespace AsbCloudInfrastructure.Repository return query; } + [Obsolete] public async Task> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) { var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs index 17f76a33..517b98ef 100644 --- a/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs +++ b/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs @@ -6,8 +6,8 @@ namespace AsbCloudWebApi.IntegrationTests.Clients; public interface IGtrWitsClient { - private const string BaseRoute = "/api/well/{idWell}/gtrWits"; + private const string BaseRoute = "/api/gtrWits"; [Get(BaseRoute)] - Task>> GetAllAsync(int idWell, [Query] GtrRequestBase request); + Task>> GetAllAsync(int idWell, [Query] GtrRequest request); } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs b/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs index eb1e96d8..e951c13e 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs @@ -26,7 +26,7 @@ public class GtrControllerTests : BaseIntegrationTest dbContext.WitsItemFloat.AddRange(witsItems); await dbContext.SaveChangesAsync(); - var request = new GtrRequestBase(); + var request = new GtrRequest(); //act var response = await client.GetAllAsync(well.Id, request); diff --git a/AsbCloudWebApi/Controllers/GtrWitsController.cs b/AsbCloudWebApi/Controllers/GtrWitsController.cs deleted file mode 100644 index 69d8a7d2..00000000 --- a/AsbCloudWebApi/Controllers/GtrWitsController.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data.GTR; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Repositories; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; - -namespace AsbCloudWebApi.Controllers; - -[ApiController] -[Route("api/well/{idWell}/[controller]")] -[Authorize] -public class GtrWitsController : ControllerBase -{ - private readonly IWellService wellService; - private readonly IGtrRepository gtrRepository; - - public GtrWitsController(IWellService wellService, - IGtrRepository gtrRepository) - { - this.wellService = wellService; - this.gtrRepository = gtrRepository; - } - - /// - /// Получить значение от ГТИ - /// - /// - /// - /// - /// - [HttpGet] - [Permission] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task GetAllAsync(int idWell, [FromQuery] GtrRequestBase request, CancellationToken token) - { - await AssertUserHasAccessToWellAsync(idWell, token); - - var requestToRepository = new GtrRequest(idWell, request); - - var dtos = await gtrRepository.GetAsync(requestToRepository, token); - - return Ok(dtos); - } - - private async Task AssertUserHasAccessToWellAsync(int idWell, CancellationToken token) - { - var idUser = User.GetUserId(); - var idCompany = User.GetCompanyId(); - - if (!idUser.HasValue) - throw new ForbidException("Нет доступа к скважине"); - - if (!idCompany.HasValue) - throw new ForbidException("Нет доступа к скважине"); - - if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token)) - throw new ForbidException("Нет доступа к скважине"); - } -} \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs index 95662fe2..8f38b2ad 100644 --- a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs @@ -8,7 +8,9 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Exceptions; using AsbCloudApp.Requests; +using Microsoft.AspNetCore.Http; namespace AsbCloudWebApi.Controllers.SAUB { @@ -36,6 +38,25 @@ namespace AsbCloudWebApi.Controllers.SAUB this.wellService = wellService; this.telemetryHubContext = telemetryHubContext; } + + /// + /// Получить значение от ГТИ + /// + /// + /// + /// + /// + [HttpGet] + [Permission] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task GetAllAsync(int idWell, [FromQuery] GtrRequest request, CancellationToken token) + { + await AssertUserHasAccessToWellAsync(idWell, token); + + var dtos = await gtrRepository.GetAsync(idWell, request, token); + + return Ok(dtos); + } /// /// Получить загруженные данные ГТИ по скважине @@ -114,6 +135,21 @@ namespace AsbCloudWebApi.Controllers.SAUB .SendAsync(SignalRMethodGetDataName, dtos), CancellationToken.None); return Ok(); } + + private async Task AssertUserHasAccessToWellAsync(int idWell, CancellationToken token) + { + var idUser = User.GetUserId(); + var idCompany = User.GetCompanyId(); + + if (!idUser.HasValue) + throw new ForbidException("Нет доступа к скважине"); + + if (!idCompany.HasValue) + throw new ForbidException("Нет доступа к скважине"); + + if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token)) + throw new ForbidException("Нет доступа к скважине"); + } } } From 200b0e3ae596ea4cb7f2c0e4627d2d5fdc21bb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 10 Apr 2024 06:27:51 +0300 Subject: [PATCH 3/5] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=88=D0=B0?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Templates/ProcessMapPlanReamTemplate.xlsx | Bin 7912 -> 48997 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Templates/ProcessMapPlanReamTemplate.xlsx b/AsbCloudInfrastructure/Services/ProcessMapPlan/Templates/ProcessMapPlanReamTemplate.xlsx index 5217eb02c2e65ad757890bc8bfef1ed4a29aa5b3..5f5be35bfd62215272aeead11ffc54df97cc49c8 100644 GIT binary patch literal 48997 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 NGPV%qAENQM{{v`ry1W1Y literal 7912 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 From a91d4888e62503f3db0b19f0b868bd9eb84be4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 10 Apr 2024 09:09:48 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=8D=D0=BB=D0=B5=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=20Wits?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/GtrWitsRepository.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs index 022532f2..57b36ef2 100644 --- a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs +++ b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Exceptions; using AsbCloudApp.Requests; using Mapster; @@ -19,7 +20,7 @@ namespace AsbCloudInfrastructure.Repository { public class GtrWitsRepository : IGtrRepository { - private static IDictionary<(int, int), string> WitsParameters = new Dictionary<(int, int), string> + private static IDictionary<(int IdRecord, int IdItem), string> WitsParameters = new Dictionary<(int, int), string> { { (1, 8), nameof(GtrWitsDto.DEPTBITM) }, { (1, 10), nameof(GtrWitsDto.DEPTMEAS) }, @@ -90,8 +91,10 @@ namespace AsbCloudInfrastructure.Repository if (telemetry is null) return Enumerable.Empty(); - var timezone = telemetryService.GetTimezone(telemetry.Id); - var timezoneOffset = TimeSpan.FromHours(timezone.Hours); + if (telemetry.TimeZone is null) + throw new ArgumentInvalidException(nameof(idWell),$"Telemetry id: {telemetry.Id} can't find timezone"); + + var timezoneOffset = TimeSpan.FromHours(telemetry.TimeZone.Hours); var query = BuildQuery(telemetry.Id, request); @@ -100,7 +103,10 @@ namespace AsbCloudInfrastructure.Repository var interval = TimeSpan.FromSeconds(10); + var idsRecord = WitsParameters.Select(p => p.Key.IdRecord); + var entities = await query + .Where(e => idsRecord.Contains(e.IdRecord)) .OrderBy(e => e.DateTime) .AsNoTracking() .ToArrayAsync(token); From ed2d4ae01b626176dcef07809adadecbc14b4eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 10 Apr 2024 13:05:20 +0300 Subject: [PATCH 5/5] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=8D=D0=BA?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D1=80=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProcessMapPlan/Export/ProcessMapPlanExportService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Export/ProcessMapPlanExportService.cs b/AsbCloudInfrastructure/Services/ProcessMapPlan/Export/ProcessMapPlanExportService.cs index 458877d1..07cc6a13 100644 --- a/AsbCloudInfrastructure/Services/ProcessMapPlan/Export/ProcessMapPlanExportService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMapPlan/Export/ProcessMapPlanExportService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -26,7 +27,11 @@ public abstract class ProcessMapPlanExportService : ExportExcelService> GetDtosAsync(WellRelatedExportRequest options, CancellationToken token) { - var request = new ProcessMapPlanBaseRequestWithWell(options.IdWell); + var request = new ProcessMapPlanBaseRequestWithWell(options.IdWell) + { + Moment = DateTimeOffset.UtcNow + }; + var dtos = await processMapPlanRepository.Get(request, token); return dtos; }