using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudApp.Services.ProcessMaps; using AsbCloudApp.Services.ProcessMaps.WellDrillingProcessMap; using AsbCloudWebApi.SignalR; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; namespace AsbCloudWebApi.Controllers.ProcessMaps; public class WellDrillingProcessMapController : ProcessMapBaseController<WellDrillingProcessMapDto> { private readonly IHubContext<TelemetryHub> telemetryHubContext; private readonly IWellDrillingProcessMapReportService wellDrillingProcessMapReportService; private readonly IProcessMapReportExportService wellDrillingProcessMapReportExportService; private readonly IProcessMapImportService wellDrillingProcessMapImportService; private readonly ICrudRepository<WellSectionTypeDto> wellSectionRepository; public WellDrillingProcessMapController(IWellService wellService, IWellDrillingProcessMapRepository repository, IUserRepository userRepository, IHubContext<TelemetryHub> telemetryHubContext, IProcessMapReportExportService wellDrillingProcessMapReportExportService, IProcessMapImportService wellDrillingProcessMapImportService, IWellDrillingProcessMapReportService wellDrillingProcessMapReportService, ICrudRepository<WellSectionTypeDto> wellSectionRepository) : base(wellService, repository, userRepository) { this.telemetryHubContext = telemetryHubContext; this.wellDrillingProcessMapReportExportService = wellDrillingProcessMapReportExportService; this.wellDrillingProcessMapImportService = wellDrillingProcessMapImportService; this.wellDrillingProcessMapReportService = wellDrillingProcessMapReportService; this.wellSectionRepository = wellSectionRepository; } /// <summary> /// Создание РТК /// </summary> /// <param name="processMap">Тело запроса</param> /// <param name="idWell">Id скважины</param> /// <param name="cancellationToken"></param> /// <returns></returns> public override async Task<IActionResult> InsertAsync(WellDrillingProcessMapDto processMap, int idWell, CancellationToken cancellationToken) { await CheckIsExistsWellSectionTypeAsync(processMap.IdWellSectionType, cancellationToken); var result = await base.InsertAsync(processMap, idWell, cancellationToken); await NotifyUsersBySignalR(idWell, cancellationToken); return result; } /// <summary> /// Обновление РТК /// </summary> /// <param name="processMap">Тело запроса</param> /// <param name="idWell">Id скважины</param> /// <param name="cancellationToken"></param> /// <returns></returns> public override async Task<IActionResult> UpdateAsync(WellDrillingProcessMapDto processMap, int idWell, CancellationToken cancellationToken) { await CheckIsExistsWellSectionTypeAsync(processMap.IdWellSectionType, cancellationToken); var result = await base.UpdateAsync(processMap, idWell, cancellationToken); await NotifyUsersBySignalR(idWell, cancellationToken); return result; } /// <summary> /// Удаление РТК /// </summary> /// <param name="idWell">Id скважины</param> /// <param name="cancellationToken"></param> /// <returns></returns> public override async Task<IActionResult> DeleteAsync(int idWell, CancellationToken cancellationToken) { var result = await base.DeleteAsync(idWell, cancellationToken); await NotifyUsersBySignalR(idWell, cancellationToken); return result; } /// <summary> /// Получение отчета РТК бурение /// </summary> /// <param name="idWell">Id</param> /// <param name="cancellationToken"></param> /// <returns></returns> [HttpGet("report")] [ProducesResponseType(typeof(WellDrillingProcessMapDto), StatusCodes.Status200OK)] public async Task<IActionResult> GetReportAsync(int idWell, CancellationToken cancellationToken) { var report = await wellDrillingProcessMapReportService.GetAsync(idWell, cancellationToken); return Ok(report); } /// <summary> /// Экспорт отчета РТК бурение /// </summary> /// <param name="idWell">Id скважины</param> /// <param name="cancellationToken"></param> /// <returns></returns> [HttpGet("report/export")] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task<IActionResult> ExportReportAsync(int idWell, CancellationToken cancellationToken) { var report = await wellDrillingProcessMapReportExportService.ExportAsync(idWell, cancellationToken); if (report is null) return NoContent(); return File(report.Value.File, "application/octet-stream", report.Value.Name); } /// <summary> /// Импорт РТК бурение /// </summary> /// <param name="idWell">Id скважины</param> /// <param name="options"></param> /// <param name="file"></param> /// <param name="cancellationToken"></param> /// <returns></returns> [HttpPost("import/{options}")] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task<IActionResult> ImportAsync(int idWell, int options, [Required] IFormFile file, CancellationToken cancellationToken) { await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken); if (Path.GetExtension(file.FileName).ToLower() != ".xlsx") return this.ValidationBadRequest(nameof(file), "Требуется xlsx файл."); using Stream stream = file.OpenReadStream(); try { await wellDrillingProcessMapImportService.ImportAsync(idWell, IdUser, (options & 1) > 0, stream, cancellationToken); } catch (FileFormatException ex) { return this.ValidationBadRequest(nameof(file), ex.Message); } return Ok(); } /// <summary> /// Экспорт РТК бурение /// </summary> /// <param name="idWell">Id скважины</param> /// <param name="cancellationToken"></param> /// <returns></returns> [HttpGet("export")] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task<IActionResult> ExportAsync(int idWell, CancellationToken cancellationToken) { var processMapsFile = await wellDrillingProcessMapImportService.ExportAsync(idWell, cancellationToken); return File(processMapsFile.File, "application/octet-stream", processMapsFile.Name); } /// <summary> /// Возвращает шаблон файла для импорта /// </summary> /// <returns>Запрашиваемый файл</returns> [HttpGet("template")] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")] public async Task<IActionResult> GetTemplateAsync(CancellationToken cancellationToken) { var template = await wellDrillingProcessMapImportService.GetExcelTemplateStreamAsync(cancellationToken); return File(template.File, "application/octet-stream", template.Name); } private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken) { var wellSection = await wellSectionRepository.GetOrDefaultAsync(idWellSectionType, cancellationToken); if (wellSection is null) throw new ArgumentInvalidException(nameof(WellDrillingProcessMapDto.IdWellSectionType), $"Тип секции с Id: {idWellSectionType} не найден"); } private async Task NotifyUsersBySignalR(int idWell, CancellationToken cancellationToken) { var wellDrillingProcessMaps = await repository.GetByIdWellAsync(idWell, cancellationToken); await telemetryHubContext.Clients .Group($"well_{idWell}") .SendAsync("UpdateProcessMap", wellDrillingProcessMaps, cancellationToken); } }