using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Requests.ExportOptions; using AsbCloudApp.Requests.ParserOptions; using AsbCloudApp.Services; using AsbCloudApp.Services.Export; using AsbCloudApp.Services.Parsers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudWebApi.Controllers.ProcessMaps; /// /// РТК план базовый /// [ApiController] [Route("api/well/{idWell}/[controller]")] [Authorize] public abstract class ProcessMapPlanBaseController : ControllerBase where TDto : ProcessMapPlanBaseDto { private readonly IChangeLogRepository repository; private readonly IWellService wellService; private readonly IParserService parserService; private readonly ITelemetryService telemetryService; private readonly IExportService processMapPlanExportService; protected ProcessMapPlanBaseController(IChangeLogRepository repository, IWellService wellService, IParserService parserService, IExportService processMapPlanExportService, ITelemetryService telemetryService) { this.repository = repository; this.wellService = wellService; this.parserService = parserService; this.telemetryService = telemetryService; this.processMapPlanExportService = processMapPlanExportService; } protected abstract string TemplateFileName { get; } /// /// Добавление /// /// /// /// /// [HttpPost] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task InsertRange([FromRoute][Range(0, int.MaxValue)] int idWell, IEnumerable dtos, CancellationToken token) { var idUser = await AssertUserHasAccessToWell(idWell, token); foreach (var dto in dtos) dto.IdWell = idWell; var result = await repository.InsertRange(idUser, dtos, token); return Ok(result); } /// /// Удалить все по скважине и добавить новые /// /// /// /// /// [HttpPost("replace")] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task ClearAndInsertRange([FromRoute] int idWell, IEnumerable dtos, CancellationToken token) { var idUser = await AssertUserHasAccessToWell(idWell, token); foreach (var dto in dtos) dto.IdWell = idWell; var request = new ProcessMapPlanBaseRequestWithWell(idWell); var result = await repository.ClearAndInsertRange(idUser, request, dtos, token); return Ok(result); } /// /// Пометить записи как удаленные /// /// /// /// /// [HttpDelete] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task MarkAsDeleted([FromRoute] int idWell, IEnumerable ids, CancellationToken token) { var idUser = await AssertUserHasAccessToWell(idWell, token); var result = await repository.MarkAsDeleted(idUser, ids, token); return Ok(result); } /// /// Очистка /// /// /// /// [HttpDelete("clear")] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task Clear([FromRoute] int idWell, CancellationToken token) { var idUser = await AssertUserHasAccessToWell(idWell, token); var request = new ProcessMapPlanBaseRequestWithWell(idWell); var result = await repository.Clear(idUser, request, token); return Ok(result); } /// /// Получение текущих записей по параметрам /// /// /// /// [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>> GetCurrent([FromRoute] int idWell, CancellationToken token) { await AssertUserHasAccessToWell(idWell, token); var serviceRequest = new ProcessMapPlanBaseRequestWithWell(idWell); var result = await repository.GetCurrent(serviceRequest, token); return Ok(result); } /// /// Получение измененных записей за определенную дату по ключу скважины /// /// /// /// /// [HttpGet("history")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>>> GetHistory([FromRoute] int idWell, DateTimeOffset? moment, CancellationToken token) { await AssertUserHasAccessToWell(idWell, token); var serviceRequest = new ProcessMapPlanBaseRequestWithWell(idWell) { Moment = moment, }; var result = await repository.GetChangeLog(serviceRequest, null, token); return Ok(result); } /// /// Получение записей за определенную дату по uid /// /// /// /// /// [AllowAnonymous] [HttpGet("/api/telemetry/{uid}/[controller]")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>>> GetByUid(string uid, DateTimeOffset? updateFrom, CancellationToken token) { var idWell = telemetryService.GetIdWellByTelemetryUid(uid) ?? -1; if (idWell < 0) return this.ValidationBadRequest(nameof(uid), "Скважина по uid не найдена"); var serviceRequest = new ProcessMapPlanBaseRequestWithWell(new ProcessMapPlanBaseRequest() { UpdateFrom = updateFrom, }, idWell); var result = await repository.GetChangeLog(serviceRequest, null, token); return Ok(result); } /// /// Изменения за определенную дату /// /// /// /// /// [HttpGet("changeLog")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>>> GetChangeLog([FromRoute] int idWell, [FromQuery] DateOnly? date, CancellationToken token) { await AssertUserHasAccessToWell(idWell, token); var serviceRequest = new ProcessMapPlanBaseRequestWithWell(idWell); var result = await repository.GetChangeLog(serviceRequest, date, token); return Ok(result); } /// /// Даты за которые есть изменения /// /// /// /// [HttpGet("dates")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>> GetDatesChange([FromRoute] int idWell, CancellationToken token) { await AssertUserHasAccessToWell(idWell, token); var serviceRequest = new ProcessMapPlanBaseRequestWithWell(idWell); var result = await repository.GetDatesChange(serviceRequest, token); return Ok(result); } /// /// Редактирование или добавление [для пакетного редактирования] /// /// /// /// /// [HttpPut()] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task UpdateOrInsertRange([FromRoute] int idWell, IEnumerable dtos, CancellationToken token) { if (!dtos.Any()) return NoContent(); var idUser = await AssertUserHasAccessToWell(idWell, token); foreach (var dto in dtos) dto.IdWell = idWell; var result = await repository.UpdateOrInsertRange(idUser, dtos, token); return Ok(result); } /// /// Импорт РТК из excel (xlsx) файла /// /// /// /// /// [HttpPost("parse")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>> Parse(int idWell, [Required] IFormFile file, CancellationToken token) { await AssertUserHasAccessToWell(idWell, token); var stream = file.GetExcelFile(); try { var options = new WellRelatedParserRequest(idWell); var dto = parserService.Parse(stream, options); return Ok(dto); } catch (FileFormatException ex) { return this.ValidationBadRequest(nameof(file), ex.Message); } } /// /// Получение шаблона для заполнения РТК /// /// [HttpGet("template")] [AllowAnonymous] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")] [ProducesResponseType(StatusCodes.Status204NoContent)] public IActionResult GetTemplate() { var stream = parserService.GetTemplateFile(); return File(stream, "application/octet-stream", TemplateFileName); } /// /// returns user id, if he has access to well /// /// /// /// /// private async Task AssertUserHasAccessToWell(int idWell, CancellationToken token) { var idUser = GetUserId(); var idCompany = User.GetCompanyId(); if (!idCompany.HasValue) throw new ForbidException("Нет доступа к скважине"); if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token)) throw new ForbidException("Нет доступа к скважине"); return idUser; } /// /// Формируем excel файл с текущими строками РТК /// /// id скважины /// /// Запрашиваемый файл [HttpGet("export")] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task ExportAsync([FromRoute] int idWell, CancellationToken token) { var exportOptions = new WellRelatedExportRequest(idWell); var (fileName, file) = await processMapPlanExportService.ExportAsync(exportOptions, token); return File(file, "application/octet-stream", fileName); } /// /// returns user id or throw /// /// /// private int GetUserId() { var idUser = User.GetUserId() ?? throw new ForbidException("Неизвестный пользователь"); return idUser; } }