using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudWebApi.SignalR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; namespace AsbCloudWebApi.Controllers.ProcessMaps; /// /// РТК /// [ApiController] [Route("api/well/{idWell}/[controller]")] [Authorize] public abstract class ProcessMapBaseController : ControllerBase where T : ProcessMapPlanBaseDto { private readonly IHubContext telemetryHubContext; private readonly ITelemetryService telemetryService; public abstract string SignalRMethod { get; } protected int IdUser { get { var idUser = User.GetUserId(); if (!idUser.HasValue) throw new ForbidException("Неизвестный пользователь"); return idUser.Value; } } private readonly IWellService wellService; private readonly IUserRepository userRepository; private readonly ICrudRepository wellSectionRepository; protected readonly IProcessMapPlanRepository repository; protected ProcessMapBaseController(IWellService wellService, IProcessMapPlanRepository repository, IUserRepository userRepository, ICrudRepository wellSectionRepository, IHubContext telemetryHubContext, ITelemetryService telemetryService) { this.wellService = wellService; this.repository = repository; this.userRepository = userRepository; this.wellSectionRepository = wellSectionRepository; this.telemetryHubContext = telemetryHubContext; this.telemetryService = telemetryService; } /// /// Создание плановой РТК /// /// Тело запроса /// Id скважины /// /// [HttpPost] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public virtual async Task InsertAsync(T processMap, int idWell, CancellationToken cancellationToken) { processMap.IdWell = idWell; processMap.IdUser = IdUser; processMap.LastUpdate = DateTime.UtcNow; await CheckIsExistsWellSectionTypeAsync(processMap.IdWellSectionType, cancellationToken); await AssertUserHasAccessToEditProcessMapAsync(processMap.IdWell, cancellationToken); var result = await repository.InsertAsync(processMap, cancellationToken); await NotifyUsersBySignalR(idWell, cancellationToken); return Ok(result); } /// /// Обновление плановой РТК /// /// Тело запроса /// Id скважины /// /// [HttpPut] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public virtual async Task UpdateAsync(T processMap, int idWell, CancellationToken cancellationToken) { processMap.IdWell = idWell; processMap.IdUser = IdUser; processMap.LastUpdate = DateTime.UtcNow; await CheckIsExistsWellSectionTypeAsync(processMap.IdWellSectionType, cancellationToken); await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken); var result = await repository.UpdateAsync(processMap, cancellationToken); if (result == ICrudRepository.ErrorIdNotFound) return this.ValidationBadRequest(nameof(processMap.Id), $"РТК с Id: {processMap.Id} не существует"); await NotifyUsersBySignalR(idWell, cancellationToken); return Ok(result); } /// /// Удаление плановой РТК /// /// Id удаляемой РТК /// Id скважины /// /// [HttpDelete] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] public virtual async Task DeleteAsync(int id, int idWell, CancellationToken cancellationToken) { await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken); var result = await repository.DeleteAsync(id, cancellationToken); await NotifyUsersBySignalR(idWell, cancellationToken); return Ok(result); } /// /// Получение РТК по Id скважины /// /// Id скважины /// /// [HttpGet] public async Task>> GetAsync(int idWell, CancellationToken cancellationToken) { var processMaps = await repository.GetByIdWellAsync(idWell, cancellationToken); return Ok(processMaps); } /// /// Получение РТК по телеметрии /// /// Уникальный ключ телеметрии /// Дата с которой требуется получить РТК /// /// [HttpGet("/api/telemetry/{uid}/[controller]")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>> GetProcessMapPlanByTelemetry(string uid, DateTime updateFrom, CancellationToken cancellationToken) { var idWell = telemetryService.GetIdWellByTelemetryUid(uid); if (!idWell.HasValue) return this.ValidationBadRequest(nameof(uid), $"Wrong uid {uid}"); var wellDrillingProcessMaps = await repository.GetAsync(new[] { new ProcessMapPlanRequest { IdWell = idWell.Value, UpdateFrom = updateFrom }}, cancellationToken); return Ok(wellDrillingProcessMaps); } protected async Task AssertUserHasAccessToEditProcessMapAsync(int idWell, CancellationToken cancellationToken) { var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken) ?? throw new ArgumentInvalidException(nameof(idWell), $"Скважины с {idWell} не существует"); var idCompany = User.GetCompanyId(); if (!idCompany.HasValue || !await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, cancellationToken)) throw new ForbidException("Нет доступа к скважине"); if (well.IdState == 2 && !userRepository.HasPermission(IdUser, "ProcessMap.editCompletedWell")) throw new ForbidException("Недостаточно прав для редактирования РТК завершенной скважины"); } protected async Task NotifyUsersBySignalR(int idWell, CancellationToken cancellationToken) { var dtos = await repository.GetByIdWellAsync(idWell, cancellationToken); await telemetryHubContext.Clients .Group($"{SignalRMethod}_{idWell}") .SendAsync("UpdateProcessMap", dtos, cancellationToken); } private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken) { var wellSection = await wellSectionRepository.GetOrDefaultAsync(idWellSectionType, cancellationToken); if (wellSection is null) throw new ArgumentInvalidException(nameof(ProcessMapPlanWellDrillingDto.IdWellSectionType), $"Тип секции с Id: {idWellSectionType} не найден"); } }