Merge branch 'reports' into dev

This commit is contained in:
Фролов 2021-09-23 10:55:18 +05:00
commit 4ef8702948
21 changed files with 193 additions and 181 deletions

View File

@ -0,0 +1,10 @@
namespace AsbCloudApp.Data
{
public class ReportProgressDto
{
public float Progress { get; set; }
public string Operation { get; set; }
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
}
}

View File

@ -6,7 +6,7 @@ namespace AsbCloudApp.Data
{
public int Id { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public string Url { get; set; }
public int IdWell { get; set; }
public DateTime Date { get; set; }
public DateTimeOffset Begin { get; set; }

View File

@ -24,6 +24,8 @@ namespace AsbCloudApp.Services
CancellationToken token = default);
Task<IEnumerable<FileInfoDto>> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token = default);
Task<int> DeletedAsync(int id, CancellationToken token);
string GetFileName(FileInfoDto fileInfo);
string GetUrl(FileInfoDto fileInfo);
string GetUrl(int idFile);
string GetUrl(int idWell, int idCategory, int idFile, string dotExtention);
}
}

View File

@ -11,14 +11,15 @@ namespace AsbCloudApp.Services
int ReportCategoryId { get; }
int CreateReport(int idWell, int idUser, int stepSeconds,
int format, DateTime begin, DateTime end,
Action<float, string, int> handleReportProgress,
Action<string, int> handleReportName);
Action<object, int> handleReportProgress);
int GetReportPagesCount(int idWell, DateTime begin, DateTime end,
int stepSeconds, int format);
Task<IEnumerable<ReportPropertiesDto>> GetSuitableReportsAsync(int idWell,
Task<List<ReportPropertiesDto>> GetSuitableReportsAsync(int idWell,
DateTime begin, DateTime end, int stepSeconds, int format,
CancellationToken token);
Task<DatesRangeDto> GetReportsDatesRangeAsync(int idWell,
CancellationToken token);
Task<List<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token);
}
}

View File

@ -5,11 +5,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.10" />
</ItemGroup>
</Project>

View File

@ -54,6 +54,7 @@ namespace AsbSaubReport
Customer = well.RelationCompaniesWells.FirstOrDefault(c => c.Company.IdCompanyType == 1)?.Company.Caption,
DrillingStartDate = well.Telemetry?.Info?.DrillingStartDate ?? default,
TimeZoneId = well.Telemetry?.Info?.TimeZoneId ?? default,
TimeZoneOffsetTotalHours = well.Telemetry?.Info?.TimeZoneOffsetTotalHours ?? default,
};
}
@ -62,19 +63,19 @@ namespace AsbSaubReport
var messagesStat = (from item in context.TelemetryMessages
where item.IdTelemetry == idTelemetry
group item.Date by item.IdTelemetry into g
select new { min = g.Min(), max = g.Max(), count = g.Count()})
select new { min = g.Min(), max = g.Max(), count = g.Count() })
.FirstOrDefault();
var dataStat = (from item in context.TelemetryDataSaub
where item.IdTelemetry == idTelemetry
where item.IdTelemetry == idTelemetry
group item.Date by item.IdTelemetry into g
select new { min = g.Min(), max = g.Max(), count = g.Count() })
.FirstOrDefault();
var result = new AnalyzeResult
{
MinDate = dataStat?.max ?? messagesStat?.min ?? default,
MaxDate = dataStat?.max ?? messagesStat?.min ?? default,
MinDate = dataStat?.min ?? messagesStat?.min ?? default,
MaxDate = dataStat?.max ?? messagesStat?.max ?? default,
MessagesCount = messagesStat?.count ?? 0,
};
@ -86,6 +87,7 @@ namespace AsbSaubReport
where item.IdTelemetry == idTelemetry
&& item.Date >= begin
&& item.Date <= end
orderby item.Date
select new DataSaubReport
{
Id = item.Id,
@ -115,6 +117,7 @@ namespace AsbSaubReport
where item.IdTelemetry == idTelemetry
&& item.Date >= begin
&& item.Date <= end
orderby item.Date
select new MessageReport
{
Id = item.Id,

View File

@ -55,7 +55,7 @@ namespace AsbCloudInfrastructure.Services
var fileNames = filesInfos
.Where(f => f.Name != resultFileName)
.Select(f => fileService.GetFileName(f));
.Select(f => fileService.GetUrl(f));
var stream = new MemoryStream(1024 * 1024);
UniteExcelFiles(fileNames, stream);

View File

@ -52,10 +52,8 @@ namespace AsbCloudInfrastructure.Services
Directory.CreateDirectory(Path.GetDirectoryName(relativePath));
using (var newfileStream = new FileStream(relativePath, FileMode.Create))
{
await fileStream.CopyToAsync(newfileStream);
}
using var newfileStream = new FileStream(relativePath, FileMode.Create);
await fileStream.CopyToAsync(newfileStream, token).ConfigureAwait(false);
var dto = entry.Entity.Adapt<FileInfoDto>();
return dto;
@ -164,7 +162,7 @@ namespace AsbCloudInfrastructure.Services
if (fileInfo is null)
return 0;
var fileName = GetFileName(fileInfo.Adapt<FileInfoDto>());
var fileName = GetUrl(fileInfo.Adapt<FileInfoDto>());
if (File.Exists(fileName))
File.Delete(fileName);
@ -172,12 +170,22 @@ namespace AsbCloudInfrastructure.Services
return await db.SaveChangesAsync(token).ConfigureAwait(false);
}
public string GetFileName(FileInfoDto fileInfo)
public string GetUrl(FileInfoDto fileInfo) =>
GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name));
public string GetUrl(int idFile)
{
var fileName = $"{fileInfo.Id}{Path.GetExtension(fileInfo.Name)}";
fileName = Path.Combine(RootPath, fileInfo.IdWell.ToString(), fileInfo.IdCategory.ToString(), fileName);
fileName = Path.GetFullPath(fileName);
return fileName;
var fileInfo = db.Files
.FirstOrDefault(f => f.Id == idFile);
if (fileInfo is null)
return null;
return GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name));
}
public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) =>
Path.Combine(RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}");
}
}

View File

@ -2,7 +2,7 @@
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbSaubReport;
using AsbSaubReportPdf;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
@ -39,90 +39,66 @@ namespace AsbCloudInfrastructure.Services
public int ReportCategoryId { get; private set; }
public int CreateReport(int idWell, int idUser, int stepSeconds, int format, DateTime begin,
DateTime end, Action<float, string, int> progressHandler, Action<string, int> reportNameHandler)
DateTime end, Action<object, int> progressHandler)
{
var newReportId = queue.EnqueueTask((id) =>
{
var optionsBuilder = new DbContextOptionsBuilder<AsbCloudDbContext>();
optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection"));
var tempDir = Path.Combine(Path.GetTempPath(), "report");
using (var context = new AsbCloudDbContext(optionsBuilder.Options))
using var context = new AsbCloudDbContext(optionsBuilder.Options);
var generator = GetReportGenerator(idWell, begin, end, stepSeconds, format, context);
var reportFileName = Path.Combine(tempDir, generator.GetReportDefaultFileName());
var totalPages = generator.GetPagesCount();
generator.OnProgress += (s, e) =>
{
var generator = GetReportGenerator(idWell, begin, end, stepSeconds, format, context);
generator.OnProgress += (s, e) => progressHandler.Invoke(e.progress, e.operation, id);
progressHandler.Invoke(e.Adapt<ReportProgressDto>(), id);
};
generator.Make(reportFileName);
var reportFileName = GetReportFileName(context, idWell);
var fileService = new FileService(context);
using var filestream = File.OpenRead(reportFileName);
var fileInfo = fileService.SaveAsync(idWell, idUser, ReportCategoryId, reportFileName, filestream).Result;
filestream.Close();
generator.Make(reportFileName);
if (reportFileName is not null)
{
var shorReportName = Path.GetFileName(reportFileName);
reportNameHandler.Invoke(shorReportName, id);
progressHandler.Invoke(new
{
Operation = "done",
Progress = 100f,
TotalPages = totalPages,
CurrentPage = totalPages,
file = fileInfo,
}, id);
var newReportFile = new AsbCloudDb.Model.FileInfo
{
IdWell = idWell,
IdAuthor = idUser,
IdCategory = ReportCategoryId,
Name = reportFileName,
UploadDate = DateTime.Now,
};
context.Files.Add(newReportFile);
var newReportProperties = new ReportProperty
{
IdWell = idWell,
IdFile = newReportFile.Id,
Begin = begin,
End = end,
Step = stepSeconds,
Format = format
};
context.ReportProperties.Add(newReportProperties);
context.SaveChanges();
}
}
var newReportProperties = new ReportProperty
{
IdWell = idWell,
IdFile = fileInfo.Id,
Begin = begin,
End = end,
Step = stepSeconds,
Format = format
};
context.ReportProperties.Add(newReportProperties);
context.SaveChanges();
});
progressHandler.Invoke(new ReportProgressDto
{
Operation = "Ожидает начала в очереди.",
Progress = 0f,
}, newReportId);
return newReportId;
}
private string GetReportFileName(AsbCloudDbContext context, int idWell)
{
var well = context.Wells.Include(w => w.Cluster).FirstOrDefault(w => w.Id == idWell);
var fileName = Path.Combine(fileService.RootPath, $"{idWell}", $"{ReportCategoryId}", $"Рапорт куст{well?.Cluster?.Caption} скв{well.Caption}.pdf") ;
return fileName;
}
public int GetReportPagesCount(int idWell, DateTime begin, DateTime end, int stepSeconds, int format)
{
var generator = GetReportGenerator(idWell, begin, end, stepSeconds, format, (AsbCloudDbContext)db);
return generator.GetPagesCount();
}
public async Task<IEnumerable<ReportPropertiesDto>> GetSuitableReportsAsync(int idWell,
DateTime begin, DateTime end, int stepSeconds, int format, CancellationToken token = default)
{
var suitableReportsFromDb = await GetSuitableReportsFromDbAsync(idWell,
begin, end, stepSeconds, format, token).ConfigureAwait(false);
var suitableReportsProperties = suitableReportsFromDb.Select(r => new ReportPropertiesDto
{
Id = r.Id,
Name = Path.GetFileName(r.File.Name),
FullName = r.File.Name,
IdWell = r.IdWell,
Date = r.File.UploadDate,
Begin = r.Begin,
End = r.End,
Step = r.Step,
Format = r.Format == 0 ? ".pdf" : ".las"
});
return suitableReportsProperties;
}
public async Task<DatesRangeDto> GetReportsDatesRangeAsync(int idWell,
CancellationToken token = default)
{
@ -154,25 +130,53 @@ namespace AsbCloudInfrastructure.Services
};
}
private async Task<IEnumerable<ReportProperty>> GetSuitableReportsFromDbAsync(int idWell,
DateTime begin, DateTime end, int stepSeconds, int format,
CancellationToken token = default)
{
var suitableReportsNames = await (from r in db.ReportProperties.Include(r => r.File)
where r.IdWell == idWell
&& r.Begin >= begin
&& r.End <= end
&& r.Step <= stepSeconds
&& r.Format == format
select r).OrderBy(o => o.File.UploadDate)
.AsNoTracking()
.Take(512).ToListAsync(token)
.ConfigureAwait(false);
return suitableReportsNames;
}
[Obsolete]
Task<List<ReportPropertiesDto>> IReportService.GetSuitableReportsAsync(int idWell, DateTime begin, DateTime end, int stepSeconds, int format, CancellationToken token) =>
(from r in db.ReportProperties.Include(r => r.File)
where r.IdWell == idWell
&& r.Begin >= begin
&& r.End <= end
&& r.Step <= stepSeconds
&& r.Format == format
select new ReportPropertiesDto
{
Id = r.Id,
Name = r.File.Name,
Url = fileService.GetUrl(r.IdFile),
IdWell = r.IdWell,
Date = r.File.UploadDate,
Begin = r.Begin,
End = r.End,
Step = r.Step,
Format = r.Format == 0 ? ".pdf" : ".las"
})
.OrderBy(o => o.Date)
.AsNoTracking()
.Take(512).ToListAsync(token);
private IReportGenerator GetReportGenerator(int idWell, DateTime begin,
public Task<List<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token) =>
(from r in db.ReportProperties.Include(r => r.File)
where r.IdWell == idWell
select new ReportPropertiesDto
{
Id = r.Id,
Name = r.File.Name,
#pragma warning disable IDE0057 // Use range operator
Url = fileService.GetUrl(r.IdWell, ReportCategoryId, r.File.Id, r.File.Name.Substring(r.File.Name.LastIndexOf(".") > 0 ? r.File.Name.LastIndexOf(".") : r.File.Name.Length)),
#pragma warning restore IDE0057 // Use range operator
IdWell = r.IdWell,
Date = r.File.UploadDate,
Begin = r.Begin,
End = r.End,
Step = r.Step,
Format = r.Format == 0 ? ".pdf" : ".las"
})
.OrderBy(o => o.Date)
.AsNoTracking()
.Take(1024).ToListAsync(token);
private static IReportGenerator GetReportGenerator(int idWell, DateTime begin,
DateTime end, int stepSeconds, int format, AsbCloudDbContext context)
{
var dataSource = new ReportDataSourcePgCloud(context, idWell);
@ -181,11 +185,11 @@ namespace AsbCloudInfrastructure.Services
switch (format)
{
case 1: //LAS
generator = new AsbSaubReportLas.LasReprotGenerator(dataSource);
generator = new AsbSaubReportLas.ReprotGeneratorLas(dataSource);
break;
case 0: //PDF
default:
generator = new PdfReprotGenerator(dataSource);
generator = new AsbSaubReportPdf.ReprotGeneratorPdf(dataSource);
break;
}

View File

@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public abstract class TelemetryDataService<TDto, TModel> : ITelemetryDataService<TDto>, IConverter<TDto, TModel>
public abstract class TelemetryDataBaseService<TDto, TModel> : ITelemetryDataService<TDto>, IConverter<TDto, TModel>
where TDto : AsbCloudApp.Data.ITelemetryData
where TModel : class, AsbCloudDb.Model.ITelemetryData
{
@ -23,7 +23,7 @@ namespace AsbCloudInfrastructure.Services
protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers;
protected readonly CacheTable<Well> cacheWells;
public TelemetryDataService(
public TelemetryDataBaseService(
IAsbCloudDbContext db,
ITelemetryService telemetryService,
CacheDb cacheDb)

View File

@ -6,7 +6,7 @@ using Mapster;
namespace AsbCloudInfrastructure.Services
{
public class TelemetryDataSaubService: TelemetryDataService<AsbCloudApp.Data.TelemetryDataSaubDto, AsbCloudDb.Model.TelemetryDataSaub>
public class TelemetryDataSaubService: TelemetryDataBaseService<AsbCloudApp.Data.TelemetryDataSaubDto, AsbCloudDb.Model.TelemetryDataSaub>
{
public TelemetryDataSaubService(
IAsbCloudDbContext db,
@ -18,18 +18,18 @@ namespace AsbCloudInfrastructure.Services
public override TelemetryDataSaub Convert(TelemetryDataSaubDto src)
{
var entity = src.Adapt<TelemetryDataSaub>();
var telemetryUser = cacheTelemetryUsers
var telemetryUser = cacheTelemetryUsers?
.FirstOrDefault(u => u.IdTelemetry == src.IdTelemetry && (u.Name == src.User || u.Surname == src.User));
entity.IdUser = telemetryUser.IdUser;
entity.IdUser = telemetryUser?.IdUser;
return entity;
}
public override TelemetryDataSaubDto Convert(TelemetryDataSaub src)
{
var dto = src.Adapt<TelemetryDataSaubDto>();
var telemetryUser = cacheTelemetryUsers
var telemetryUser = cacheTelemetryUsers?
.FirstOrDefault(u => u.IdTelemetry == src.IdTelemetry && u.IdUser == src.IdUser);
dto.User = telemetryUser.MakeDisplayName();
dto.User = telemetryUser?.MakeDisplayName();
return dto;
}
}

View File

@ -6,7 +6,7 @@ using Mapster;
namespace AsbCloudInfrastructure.Services
{
public class TelemetryDataSpinService : TelemetryDataService<AsbCloudApp.Data.TelemetryDataSpinDto, AsbCloudDb.Model.TelemetryDataSpin>
public class TelemetryDataSpinService : TelemetryDataBaseService<AsbCloudApp.Data.TelemetryDataSpinDto, AsbCloudDb.Model.TelemetryDataSpin>
{
public TelemetryDataSpinService(
IAsbCloudDbContext db,

View File

@ -52,7 +52,7 @@ namespace AsbCloudInfrastructure.Services
}
private Telemetry GetOrCreateTelemetryByUid(string uid)
=> cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid, RefreshMode.IfResultEmpty)
=> cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid)
?? cacheTelemetry.Insert(new Telemetry { RemoteUid = uid, });
}

View File

@ -29,7 +29,7 @@ namespace AsbCloudWebApi.Controllers
.ConfigureAwait(false);
if (fileInfo is null)
return NoContent();
var relativePath = fileService.GetFileName(fileInfo);
var relativePath = fileService.GetUrl(fileInfo);
return PhysicalFile(Path.GetFullPath(relativePath), "application/octet-stream", fileInfo.Name);
}
}

View File

@ -157,8 +157,7 @@ namespace AsbCloudWebApi.Controllers
if (fileInfo is null)
throw new FileNotFoundException();
// TODO: словарь content typoв
var relativePath = fileService.GetFileName(fileInfo);
var relativePath = fileService.GetUrl(fileInfo);
return PhysicalFile(Path.GetFullPath(relativePath), "application/octet-stream", fileInfo.Name);
}
catch (FileNotFoundException ex)

View File

@ -5,8 +5,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -33,25 +31,6 @@ namespace AsbCloudWebApi.Controllers
this.reportsHubContext = reportsHubContext;
}
private void HandleReportProgressAsync(float progress, string operation, int id) =>
Task.Run(() =>
{
reportsHubContext.Clients.Group($"Report_{id}").SendAsync(
nameof(IReportHubClient.GetReportProgress),
new { Progress = progress, Operation = operation, ReportName = "" }
).ConfigureAwait(false);
});
private void HandleReportNameAsync(string reportName, int groupId) =>
Task.Run(() =>
{
reportsHubContext.Clients.All.SendAsync(
nameof(IReportHubClient.GetReportProgress),
new { Progress = 100, Operation = "Отчет успешно создан", ReportName = reportName }
).ConfigureAwait(false);
});
/// <summary>
/// Создает отчет по скважине с указанными параметрами
/// </summary>
@ -65,9 +44,44 @@ namespace AsbCloudWebApi.Controllers
/// <returns>id фоновой задачи формирования отчета</returns>
[HttpPost]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> CreateReportAsync(int idWell, int idUser, int stepSeconds, int format,
public async Task<IActionResult> CreateReportAsync(int idWell, int stepSeconds, int format,
DateTime begin = default, DateTime end = default,
CancellationToken token = default)
{
var idCompany = User.GetCompanyId();
var idUser = User.GetUserId();
if ((idCompany is null) || (idUser is null))
return Forbid();
if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
return Forbid();
void HandleReportProgressAsync(object progress, int id) =>
Task.Run(() =>
{
reportsHubContext.Clients.Group($"Report_{id}").SendAsync(
nameof(IReportHubClient.GetReportProgress),
progress
).ConfigureAwait(false);
});
var id = reportService.CreateReport(idWell, (int)idUser,
stepSeconds, format, begin, end, HandleReportProgressAsync);
return Ok(id);
}
/// <summary>
/// Возвращает имена всех отчетов по скважине
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="token">Токен для отмены задачи</param>
/// <returns>Список имен существующих отчетов (отчетов)</returns>
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<string>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetAllReportsNamesByWellAsync(int idWell, CancellationToken token = default)
{
int? idCompany = User.GetCompanyId();
@ -78,45 +92,9 @@ namespace AsbCloudWebApi.Controllers
idWell, token).ConfigureAwait(false))
return Forbid();
var id = reportService.CreateReport(idWell, idUser,
stepSeconds, format, begin, end, HandleReportProgressAsync, HandleReportNameAsync);
var reports = await reportService.GetAllReportsByWellAsync(idWell, token).ConfigureAwait(false);
return Ok(id);
}
/// <summary>
/// Возвращает файл-отчет с диска на сервере
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="reportName">имя запрашиваемого файла (отчета)</param>
/// <param name="token">Токен для отмены задачи</param>
/// <returns>файл с отчетом</returns>
[HttpGet]
[Route("{reportName}")]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetReportAsync([FromRoute] int idWell,
string reportName, CancellationToken token = default)
{
try
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
return Forbid();
// TODO: словарь content typoв
var relativePath = Path.Combine(fileService.RootPath, $"{idWell}",
$"{reportService.ReportCategoryId}", reportName);
return PhysicalFile(Path.GetFullPath(relativePath), "application/pdf", reportName);
}
catch (FileNotFoundException ex)
{
return NotFound($"Файл не найден. Текст ошибки: {ex.Message}");
}
return Ok(reports);
}
/// <summary>
@ -130,6 +108,7 @@ namespace AsbCloudWebApi.Controllers
/// <param name="end">дата окончания интервала</param>
/// <param name="token">Токен для отмены задачи</param>
/// <returns>Список имен существующих отчетов (отчетов)</returns>
[Obsolete]
[HttpGet]
[Route("suitableReports")]
[ProducesResponseType(typeof(IEnumerable<string>), (int)System.Net.HttpStatusCode.OK)]
@ -137,12 +116,18 @@ namespace AsbCloudWebApi.Controllers
DateTime begin = default, DateTime end = default,
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();
var suitableReportsNames = await reportService.GetSuitableReportsAsync(idWell,
begin, end, stepSeconds, format, token).ConfigureAwait(false);
if (suitableReportsNames is null || !suitableReportsNames.Any())
return NoContent();
return Ok(suitableReportsNames);
}