using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Repositories; using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Requests.ParserOptions; using AsbCloudInfrastructure.Services.Trajectory.Export; namespace AsbCloudWebApi.Controllers.Trajectory { /// <summary> /// Плановые и фактические траектории (загрузка и хранение) /// </summary> [ApiController] [Authorize] public abstract class TrajectoryEditableController<TDto> : TrajectoryController<TDto> where TDto : TrajectoryGeoDto { private readonly IParserService<TDto, WellRelatedParserRequest> parserService; private readonly ITrajectoryEditableRepository<TDto> trajectoryRepository; protected TrajectoryEditableController(IWellService wellService, IParserService<TDto, WellRelatedParserRequest> parserService, TrajectoryExportService<TDto> trajectoryExportService, ITrajectoryEditableRepository<TDto> trajectoryRepository) : base(wellService, trajectoryExportService, trajectoryRepository) { this.parserService = parserService; this.trajectoryRepository = trajectoryRepository; } /// <summary> /// Возвращает excel шаблон для заполнения строк траектории /// </summary> /// <returns>Запрашиваемый файл</returns> [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); } /// <summary> /// Импортирует координаты из excel (xlsx) файла /// </summary> /// <param name="idWell">id скважины</param> /// <param name="files">Коллекция из одного файла xlsx</param> /// <param name="token"> Токен отмены задачи </param> /// <returns>количество успешно записанных строк в БД</returns> [HttpPost("parse")] [ProducesResponseType((int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)] public async Task<ActionResult<ParserResultDto<TDto>>> Parse(int idWell, [FromForm] IFormFileCollection files, CancellationToken token) { var idUser = User.GetUserId(); if (!idUser.HasValue) return Forbid(); if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); var stream = files.GetExcelFile(); try { var options = new WellRelatedParserRequest(idWell); var dto = parserService.Parse(stream, options); return Ok(dto); } catch (FileFormatException ex) { return this.ValidationBadRequest(nameof(files), ex.Message); } } /// <summary> /// Добавление /// </summary> /// <param name="idWell"></param> /// <param name="dtos"></param> /// <param name="token"></param> /// <returns></returns> [HttpPost] [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] public async Task<IActionResult> InsertRangeAsync(int idWell, [FromBody] IEnumerable<TDto> dtos, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); var idUser = User.GetUserId(); if (!idUser.HasValue) return Forbid(); foreach (var dto in dtos) { dto.IdUser = idUser.Value; dto.IdWell = idWell; } var result = await trajectoryRepository.AddRangeAsync(dtos, token); return Ok(result); } /// <summary> /// Удалить все по скважине и добавить новые /// </summary> /// <param name="idWell"></param> /// <param name="dtos"></param> /// <param name="token"></param> /// <returns></returns> [HttpPost("replace")] [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] public async Task<IActionResult> ClearAndInsertRangeAsync(int idWell, [FromBody] IEnumerable<TDto> dtos, CancellationToken token) { //TODO: это вся радость требует рефакторинга. //Удаление с добавлением новых записей должно происходить в рамках одной транзакции, да и вообще должно быть реализовано на уровне репозиторий. //Рефакторинг будет когда доберёмся до журнала изменений для траекторий. if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); var idUser = User.GetUserId(); if (!idUser.HasValue) return Forbid(); foreach (var dto in dtos) { dto.IdUser = idUser.Value; dto.IdWell = idWell; } await trajectoryRepository.DeleteByIdWellAsync(idWell, token); var result = await trajectoryRepository.AddRangeAsync(dtos, token); return Ok(result); } /// <summary> /// Изменить выбранную строку с координатами /// </summary> /// <param name="idWell"></param> /// <param name="idRow"></param> /// <param name="row"></param> /// <param name="token"></param> /// <returns>количество успешно обновленных строк в БД</returns> [HttpPut("{idRow}")] [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] public async Task<IActionResult> UpdateAsync(int idWell, int idRow, [FromBody] TDto row, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) return Forbid(); int? idUser = User.GetUserId(); if (!idUser.HasValue) return Forbid(); row.Id = idRow; row.IdUser = idUser.Value; row.IdWell = idWell; var result = await trajectoryRepository.UpdateAsync(row, token); return Ok(result); } /// <summary> /// Удалить выбранную строку с координатами /// </summary> /// <param name="idWell"></param> /// <param name="idRow"></param> /// <param name="token"></param> /// <returns>количество успешно удаленных строк из БД</returns> [HttpDelete("{idRow}")] [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] public async Task<IActionResult> DeleteAsync(int idWell, int idRow, CancellationToken token) { if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) return Forbid(); var result = await trajectoryRepository.DeleteRangeAsync(new int[] { idRow }, token); return Ok(result); } } }