diff --git a/AsbCloudApp/Services/ITelemetryAnalyticsService.cs b/AsbCloudApp/Services/ITelemetryAnalyticsService.cs index 04a9ec2a..37e42ef4 100644 --- a/AsbCloudApp/Services/ITelemetryAnalyticsService.cs +++ b/AsbCloudApp/Services/ITelemetryAnalyticsService.cs @@ -24,5 +24,7 @@ namespace AsbCloudApp.Services int intervalHoursTimestamp, int workBeginTimestamp, CancellationToken token = default); void SaveAnalytics(DataSaubBaseDto dataSaub); + Task GetOperationsDateRangeAsync(int idWell, + CancellationToken token = default); } } diff --git a/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs b/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs index 99462fa9..945a15e3 100644 --- a/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs +++ b/AsbCloudInfrastructure/Services/TelemetryAnalyticsService.cs @@ -260,6 +260,36 @@ namespace AsbCloudInfrastructure.Services } } + public async Task GetOperationsDateRangeAsync(int idWell, + CancellationToken token = default) + { + var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell); + + if (telemetryId is null) + return null; + + var datesRange = await (from d in db.TelemetryAnalysis + where d.IdTelemetry == telemetryId + select d.UnixDate).DefaultIfEmpty() + .GroupBy(g => true) + .AsNoTracking() + .Select(g => new + { + From = g.Min(), + To = g.Max() + }).OrderBy(gr => gr.From) + .FirstOrDefaultAsync(token) + .ConfigureAwait(false); + + return new DatesRangeDto + { + From = DateTimeOffset.FromUnixTimeSeconds(datesRange.From).DateTime, + To = datesRange.To == default + ? DateTime.MaxValue + : DateTimeOffset.FromUnixTimeSeconds(datesRange.To).DateTime + }; + } + private static IEnumerable<(long IntervalStart, string OperationName, int OperationDuration)> DivideOperationsByIntervalLength( IEnumerable<(long IntervalStart, string OperationName, int OperationDuration)> operations, int intervalSeconds) { @@ -267,41 +297,41 @@ namespace AsbCloudInfrastructure.Services var operationDurationTimeCounter = 0; - foreach (var op in operations) + foreach (var (IntervalStart, OperationName, OperationDuration) in operations) { - if (op.OperationDuration < (intervalSeconds - operationDurationTimeCounter)) + if (OperationDuration < (intervalSeconds - operationDurationTimeCounter)) { - splittedOperationsByInterval.Add((op.IntervalStart, op.OperationName, op.OperationDuration)); - operationDurationTimeCounter += op.OperationDuration; + splittedOperationsByInterval.Add((IntervalStart, OperationName, OperationDuration)); + operationDurationTimeCounter += OperationDuration; } else { // if operation duration overflows current interval it shoud be divided into 2 or more parts for this and next intervals var remainingIntervalTime = intervalSeconds - operationDurationTimeCounter; - splittedOperationsByInterval.Add((op.IntervalStart, op.OperationName, remainingIntervalTime)); // first part of long operation + splittedOperationsByInterval.Add((IntervalStart, OperationName, remainingIntervalTime)); // first part of long operation - var operationDurationAfterDividing = op.OperationDuration - remainingIntervalTime; // second part of long operation. Can be less or more than interval + var operationDurationAfterDividing = OperationDuration - remainingIntervalTime; // second part of long operation. Can be less or more than interval // If operation duration even after dividing is still more than interval, // it should be divided several times to several intervals. if (operationDurationAfterDividing > intervalSeconds) { var counter = 0; - var updatedIntervalStartTime = op.IntervalStart + remainingIntervalTime; + var updatedIntervalStartTime = IntervalStart + remainingIntervalTime; while (operationDurationAfterDividing > intervalSeconds) { - splittedOperationsByInterval.Add((updatedIntervalStartTime + intervalSeconds * counter, op.OperationName, intervalSeconds)); + splittedOperationsByInterval.Add((updatedIntervalStartTime + intervalSeconds * counter, OperationName, intervalSeconds)); operationDurationAfterDividing -= intervalSeconds; counter++; } - splittedOperationsByInterval.Add((updatedIntervalStartTime + operationDurationAfterDividing, op.OperationName, operationDurationAfterDividing)); + splittedOperationsByInterval.Add((updatedIntervalStartTime + operationDurationAfterDividing, OperationName, operationDurationAfterDividing)); operationDurationTimeCounter = operationDurationAfterDividing; } else { - splittedOperationsByInterval.Add((op.IntervalStart, op.OperationName, operationDurationAfterDividing)); + splittedOperationsByInterval.Add((IntervalStart, OperationName, operationDurationAfterDividing)); operationDurationTimeCounter = operationDurationAfterDividing; } } diff --git a/AsbCloudWebApi/Controllers/TelemetryAnalyticsController.cs b/AsbCloudWebApi/Controllers/TelemetryAnalyticsController.cs index 4650705c..7880e039 100644 --- a/AsbCloudWebApi/Controllers/TelemetryAnalyticsController.cs +++ b/AsbCloudWebApi/Controllers/TelemetryAnalyticsController.cs @@ -170,5 +170,32 @@ namespace AsbCloudWebApi.Controllers return Ok(analytics); } + + /// + /// Возвращает даты первой и последней операций на скважине + /// + /// id скважины + /// Токен для отмены задачи + /// Даты самой первой и самой последней операций на скважине + [HttpGet] + [Route("datesRange")] + [ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)] + public async Task GetOperationsDateRangeAsync(int idWell, + CancellationToken token = default) + { + int? idCompany = User.GetCompanyId(); + + if (idCompany is null) + return Forbid(); + + if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, + idWell, token).ConfigureAwait(false)) + return Forbid(); + + DatesRangeDto wellOperationsDatesRange = await analyticsService.GetOperationsDateRangeAsync(idWell, + token).ConfigureAwait(false); + + return Ok(wellOperationsDatesRange); + } } }